diff --git a/azure_arc_k8s_jumpstart/aks/arm_template/azuredeploy.json b/azure_arc_k8s_jumpstart/aks/arm_template/azuredeploy.json index 4545de327a..81564f6ee0 100644 --- a/azure_arc_k8s_jumpstart/aks/arm_template/azuredeploy.json +++ b/azure_arc_k8s_jumpstart/aks/arm_template/azuredeploy.json @@ -121,7 +121,6 @@ "count": "[parameters('agentCount')]", "vmSize": "[parameters('agentVMSize')]", "osType": "[parameters('osType')]", - "storageProfile": "ManagedDisks", "mode": "System" } ], @@ -152,4 +151,4 @@ "value": "[reference(parameters('clusterName')).fqdn]" } } -} \ No newline at end of file +} diff --git a/azure_edge_iot_ops_jumpstart/acsa_fault_detection/yaml/acsa-edge-sub-volume.yaml b/azure_edge_iot_ops_jumpstart/acsa_fault_detection/yaml/acsa-edge-sub-volume.yaml new file mode 100644 index 0000000000..f9d01646b2 --- /dev/null +++ b/azure_edge_iot_ops_jumpstart/acsa_fault_detection/yaml/acsa-edge-sub-volume.yaml @@ -0,0 +1,13 @@ +apiVersion: "arccontainerstorage.azure.net/v1" +kind: EdgeSubvolume +metadata: + name: videos + namespace: contoso-hypermarket +spec: + edgevolume: acsa-pvc + path: videos #Don't use a preceding slash. + auth: + authType: MANAGED_IDENTITY + storageaccountendpoint: https://{STORAGEACCOUNT}.blob.core.windows.net/ + container: shopper-videos + ingestPolicy: edgeingestpolicy-default diff --git a/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-contoso-hypermarket.psd1 b/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-contoso-hypermarket.psd1 new file mode 100644 index 0000000000..6e50ce480b --- /dev/null +++ b/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-contoso-hypermarket.psd1 @@ -0,0 +1,228 @@ +@{ + # This is the PowerShell datafile used to provide configuration information for the Agora environment. Product keys and password are not encrypted and will be available on host during installation. + + # Directory paths + AgDirectories = @{ + AgDir = "C:\Ag" + AgPowerShellDir = "C:\Ag\PowerShell" + AgLogsDir = "C:\Ag\Logs" + AgVMDir = "C:\Ag\Virtual Machines" + AgIconDir = "C:\Ag\Icons" + AgTestsDir = "C:\Ag\Tests" + AgToolsDir = "C:\Tools" + AgTempDir = "C:\Temp" + AgVHDXDir = "V:\VMs" + AgConfigMapDir = "C:\Ag\ConfigMaps" + AgL1Files = "C:\Ag\L1Files" + AgAppsRepo = "C:\Ag\AppsRepo" + AgMonitoringDir = "C:\Ag\Monitoring" + AgFabric = "C:\Ag\Fabric" + } + + # Required URLs + URLs = @{ + wslUbuntu = 'https://aka.ms/wslubuntu' + wslStoreStorage = 'https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi' + docker = 'https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe' + githubAPI = 'https://api.github.com' + grafana = 'https://api.github.com/repos/grafana/grafana/releases/latest' + azurePortal = 'https://portal.azure.com' + aksEEk3s = 'https://aka.ms/aks-edge/k3s-msi' + nginx = 'https://kubernetes.github.io/ingress-nginx' + prometheus = 'https://prometheus-community.github.io/helm-charts' + vcLibs = 'https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx' + windowsTerminal = 'https://api.github.com/repos/microsoft/terminal/releases/latest' + aksEEReleases = 'https://api.github.com/repos/Azure/AKS-Edge/releases' + mqttExplorerReleases = 'https://api.github.com/repos/thomasnordquist/MQTT-Explorer/releases/latest' + } + + # Azure required registered resource providers + AzureProviders = @( + "Microsoft.Kubernetes", + "Microsoft.KubernetesConfiguration", + "Microsoft.ExtendedLocation", + "Microsoft.HybridCompute", + "Microsoft.GuestConfiguration", + "Microsoft.HybridConnectivity", + "Microsoft.DeviceRegistry", + "Microsoft.EventGrid", + "Microsoft.IoTOperationsOrchestrator", + "Microsoft.IoTOperations", + "Microsoft.Fabric" + ) + + # Az CLI required extensions + AzCLIExtensions = @( + @{name="k8s-extension"; version="latest"}, + @{name="k8s-configuration"; version="latest"}, + @{name="eventgrid"; version="latest"}, + @{name="customlocation"; version="latest"}, + @{name="kusto"; version="latest"}, + @{name="storage-preview"; version="latest"}, + @{name="azure-iot-ops"; version="latest"}, + @{name="microsoft-fabric"; version="latest"} + ) + + # PowerShell modules + PowerShellModules = @( + @{name='Az.ConnectedKubernetes'; version="0.10.3"}, + @{name='Az.KubernetesConfiguration'; version="latest"}, + @{name='Az.Kusto'; version="latest"}, + @{name='Az.EventGrid'; version="latest"}, + @{name='Az.Storage'; version="latest"}, + @{name='Az.EventHub'; version="latest"}, + @{name='powershell-yaml'; version="latest"} + ) + + # Winget packages list + WingetPackagesList = @( + 'Microsoft.AzureCLI', + 'Microsoft.PowerShell', + 'Microsoft.Bicep', + 'Kubernetes.kubectl', + 'Microsoft.Edge', + 'Microsoft.Azure.AZCopy.10', + 'Microsoft.VisualStudioCode', + 'Microsoft.AzureDataStudio', + 'Microsoft.VisualStudioCode', + 'Microsoft.SQLServerManagementStudio', + 'Git.Git', + '7zip.7zip', + 'ahmetb.kubectx', + 'PuTTY.PuTTY', + 'Helm.Helm', + 'Microsoft.DotNet.SDK.8', + 'Microsoft.Sysinternals.ZoomIt', + 'Microsoft.Sysinternals.BGInfo', + 'FireDaemon.OpenSSL', + 'thomasnordquist.MQTT-Explorer', + 'GitHub.cli', + 'Python.Python.3.12', + 'Derailed.k9s' + ) + + # Pip packages list + PipPackagesList = @( + 'paho-mqtt' + ) + + # VSCode extensions + VSCodeExtensions = @( + 'ms-vscode-remote.remote-containers', + 'ms-vscode-remote.remote-wsl', + 'ms-vscode.powershell', + 'redhat.vscode-yaml', + 'ZainChen.json', + 'esbenp.prettier-vscode', + 'ms-kubernetes-tools.vscode-kubernetes-tools', + 'mindaro.mindaro', + 'github.vscode-pull-request-github', + 'ms-mssql.mssql' + ) + + # Git branches + GitBranches = @( + 'production', + 'staging', + 'canary' , + 'main' + ) + + # VHDX blob url + ProdVHDBlobURL = 'https://jumpstartprodsg.blob.core.windows.net/agora/base/prod-w11iot/AGBase.vhdx' + PreProdVHDBlobURL = 'https://jumpstartprodsg.blob.core.windows.net/agora/base/preprod-w11iot/AGBase.vhdx' + + # L1 virtual machine configuration + HostVMDrive = "V" # This value controls the drive letter where the nested virtual + L1VMMemory = 32GB # This value controls the amount of RAM for each AKS Edge Essentials host virtual machine + L1VMNumVCPU = 8 # This value controls the number of vCPUs to assign to each AKS Edge Essentials host virtual machine. + InternalSwitch = "InternalSwitch" # This value controls the Hyper-V internal switch name used by L0 Azure virtual machine. + L1Username = "Administrator" # This value controls the Admin credential username for the L1 Hyper-V virtual machines that run on the Agora-Client. + L1Password = 'Agora123!!' # This value controls the Admin credential password for the L1 Hyper-V virtual machines that run on the Agora-Client. + L1DefaultGateway = "172.20.1.1" # This value controls the default gateway IP address used by each L1 Hyper-V virtual machines that run on the Agora-Client. + L1SwitchName = "AKS-Int" # This value controls the Hyper-V internal switch name used by each L1 Hyper-V virtual machines that run on the Agora-Client. + L1NatSubnetPrefix = "172.20.1.0/24" # This value controls the network subnet used by each L1 Hyper-V virtual machines that run on the Agora-Client. + + # NAT Configuration + natHostSubnet = "192.168.128.0/24" + natHostVMSwitchName = "InternalNAT" + natConfigure = $true + natSubnet = "192.168.46.0/24" # This value is the subnet is the NAT router will use to route to AzSMGMT to access the Internet. It can be any /24 subnet and is only used for routing. + natDNS = "%staging-natDNS%" # Do not change - can be configured by passing the optional natDNS parameter to the ARM deployment. + + # Site Kubernetes cluster configurations + SiteConfig = @{ + Seattle = @{ + ArcClusterName = "Ag-K3s-Seattle" + FriendlyName = "Seattle" + GrafanaDataSource = "seattle" + Type = "k3s" + Branch = "main" + HelmValuesFile = "prometheus-additional-scrape-config.yaml" + HelmSetValue = "alertmanager.enabled=false,grafana.enabled=false,prometheus.service.type=LoadBalancer" + HelmService = "service/prometheus-kube-prometheus-prometheus" + IsProduction = $true + } + Chicago = @{ + ArcClusterName = "Ag-K3s-Chicago" + FriendlyName = "Chicago" + GrafanaDataSource = "chicago" + Type = "k3s" + Branch = "main" + HelmValuesFile = "prometheus-additional-scrape-config.yaml" + HelmSetValue = "alertmanager.enabled=false,grafana.enabled=false,prometheus.service.type=LoadBalancer" + HelmService = "service/prometheus-kube-prometheus-prometheus" + IsProduction = $true + } + } + + # Universal resource tag and resource types + TagName = 'Project' + TagValue = 'Jumpstart_Agora' + ArcServerResourceType = 'Microsoft.HybridCompute/machines' + ArcK8sResourceType = 'Microsoft.Kubernetes/connectedClusters' + AksResourceType = 'Microsoft.ContainerService/managedClusters' + + + # Observability variables + Monitoring = @{ + AdminUser = "admin" + User = "Contoso Operator" + Email = "operator@contoso.com" + Namespace = "observability" + ProdURL = "http://localhost:3000" + Dashboards = @{ + "grafana.com" = @() # Dashboards from https://grafana.com/grafana/dashboards + "custom" = @('node-exporter-full-v2','cluster-global', 'app-workloads', 'app-pods', 'app-store-asset', 'app-store-shoppers', 'app-store-pos') # Dashboards from https://github.com/microsoft/azure_arc/tree/main/azure_jumpstart_ag/artifacts/monitoring + } + } + + Namespaces = @( + "observability" + "images-cache" + "contoso-hypermarket" + ) + + AppConfig = @{ + inferencing_deployment = @{ + GitOpsConfigName = "contoso-hypermarket" + KustomizationName = "contoso-hypermarket" + KustomizationPath="./agora/contoso_hypermarket" + Namespace = "contoso-hypermarket" + Order = 1 + } + } + + # Microsoft Edge startup settings variables + EdgeSettingRegistryPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Edge' + EdgeSettingValueTrue = '00000001' + EdgeSettingValueFalse = '00000000' + + FabricConfig = @{ + WorkspacePrefix = "contoso-hypermarket" + EventHubSharedAccessKeyName = "FabricSharedAccessKey" + EventHubName = "contoso-hypermarket" + EventHubCG = "fabriccg" + RunFabricSetupAs = "user" + } +} diff --git a/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-manufacturing.psd1 b/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-contoso-motors.psd1 similarity index 93% rename from azure_jumpstart_ag/artifacts/PowerShell/AgConfig-manufacturing.psd1 rename to azure_jumpstart_ag/artifacts/PowerShell/AgConfig-contoso-motors.psd1 index 2e600e902d..f8b4e2c433 100644 --- a/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-manufacturing.psd1 +++ b/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-contoso-motors.psd1 @@ -8,6 +8,7 @@ AgLogsDir = "C:\Ag\Logs" AgVMDir = "C:\Ag\Virtual Machines" AgIconDir = "C:\Ag\Icons" + AgTestsDir = "C:\Ag\Tests" AgToolsDir = "C:\Tools" AgTempDir = "C:\Temp" AgVHDXDir = "V:\VMs" @@ -21,7 +22,6 @@ # Required URLs URLs = @{ - chocoInstallScript = 'https://chocolatey.org/install.ps1' wslUbuntu = 'https://aka.ms/wslubuntu' wslStoreStorage = 'https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi' docker = 'https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe' @@ -70,26 +70,29 @@ @{name='Az.EventHub'; version="latest"} ) - # Chocolatey packages list - ChocolateyPackagesList = @( - 'az.powershell', - 'bicep', - 'kubernetes-cli', - 'vcredist140', - 'microsoft-edge', - 'azcopy10', - 'vscode', - 'git', - '7zip', - 'kubectx', - 'putty.install', - 'kubernetes-helm', - 'dotnet-sdk', - 'zoomit', - 'openssl.light', - 'mqtt-explorer', - 'gh', - 'python' + # Winget packages list + WingetPackagesList = @( + 'Microsoft.AzureCLI', + 'Microsoft.PowerShell', + 'Microsoft.Bicep', + 'Kubernetes.kubectl', + 'Microsoft.Edge', + 'Microsoft.Azure.AZCopy.10', + 'Microsoft.AzureDataStudio', + 'Microsoft.VisualStudioCode', + 'Microsoft.SQLServerManagementStudio', + 'Git.Git', + '7zip.7zip', + 'ahmetb.kubectx', + 'PuTTY.PuTTY', + 'Helm.Helm', + 'Microsoft.DotNet.SDK.8', + 'Microsoft.Sysinternals.ZoomIt', + 'Microsoft.Sysinternals.BGInfo', + 'FireDaemon.OpenSSL', + 'thomasnordquist.MQTT-Explorer', + 'GitHub.cli', + 'Python.Python.3.12' ) # Pip packages list diff --git a/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-retail.psd1 b/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-contoso-supermarket.psd1 similarity index 93% rename from azure_jumpstart_ag/artifacts/PowerShell/AgConfig-retail.psd1 rename to azure_jumpstart_ag/artifacts/PowerShell/AgConfig-contoso-supermarket.psd1 index 96252442d7..46ed021b4c 100644 --- a/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-retail.psd1 +++ b/azure_jumpstart_ag/artifacts/PowerShell/AgConfig-contoso-supermarket.psd1 @@ -8,6 +8,7 @@ AgLogsDir = "C:\Ag\Logs" AgVMDir = "C:\Ag\Virtual Machines" AgIconDir = "C:\Ag\Icons" + AgTestsDir = "C:\Ag\Tests" AgToolsDir = "C:\Tools" AgTempDir = "C:\Temp" AgVHDXDir = "V:\VMs" @@ -21,7 +22,6 @@ # Required URLs URLs = @{ - chocoInstallScript = 'https://chocolatey.org/install.ps1' wslUbuntu = 'https://aka.ms/wslubuntu' wslStoreStorage = 'https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi' docker = 'https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe' @@ -45,9 +45,9 @@ # Az CLI required extensions AzCLIExtensions = @( - @{name="k8s-extension"; version="latest"}, - @{name="k8s-configuration"; version="latest"}, - @{name="azure-iot"; version="latest"} + @{name = "k8s-extension"; version = "latest" }, + @{name = "k8s-configuration"; version = "latest" }, + @{name = "azure-iot"; version = "latest" } ) # PowerShell modules @@ -57,26 +57,30 @@ @{name='Az.Kusto'; version="latest"} ) - # Chocolatey packages list - ChocolateyPackagesList = @( - 'az.powershell', - 'kubernetes-cli', - 'vcredist140', - 'microsoft-edge', - 'azcopy10', - 'vscode', - 'git', - '7zip', - 'kubectx', - 'putty.install', - 'kubernetes-helm', - 'dotnet-sdk', - 'zoomit', - 'openssl.light', - 'mqtt-explorer', - 'gh', - 'python', - 'bicep' + # Winget packages list + WingetPackagesList = @( + 'Microsoft.AzureCLI', + 'Microsoft.PowerShell', + 'Microsoft.Bicep', + 'Kubernetes.kubectl', + 'Microsoft.Edge', + 'Microsoft.Azure.AZCopy.10', + 'Microsoft.VisualStudioCode', + 'Microsoft.AzureDataStudio', + 'Microsoft.VisualStudioCode', + 'Microsoft.SQLServerManagementStudio', + 'Git.Git', + '7zip.7zip', + 'ahmetb.kubectx', + 'PuTTY.PuTTY', + 'Helm.Helm', + 'Microsoft.DotNet.SDK.8', + 'Microsoft.Sysinternals.ZoomIt', + 'Microsoft.Sysinternals.BGInfo', + 'FireDaemon.OpenSSL', + 'thomasnordquist.MQTT-Explorer', + 'GitHub.cli', + 'Python.Python.3.12' ) # VSCode extensions @@ -233,7 +237,7 @@ ProdURL = "http://localhost:3000" Dashboards = @{ "grafana.com" = @() # Dashboards from https://grafana.com/grafana/dashboards - "custom" = @('freezer-monitoring','node-exporter-full','cluster-global') # Dashboards from https://github.com/microsoft/azure_arc/tree/main/azure_jumpstart_ag/retail/artifacts/monitoring + "custom" = @('freezer-monitoring','node-exporter-full','cluster-global') # Dashboards from https://github.com/microsoft/azure_arc/tree/main/azure_jumpstart_ag/contoso_supermarket/artifacts/monitoring } } diff --git a/azure_jumpstart_ag/artifacts/PowerShell/AgLogonScript.ps1 b/azure_jumpstart_ag/artifacts/PowerShell/AgLogonScript.ps1 index 357611474f..4a6d71f2c0 100644 --- a/azure_jumpstart_ag/artifacts/PowerShell/AgLogonScript.ps1 +++ b/azure_jumpstart_ag/artifacts/PowerShell/AgLogonScript.ps1 @@ -13,7 +13,9 @@ $global:AgAppsRepo = $AgConfig.AgDirectories["AgAppsRepo"] $global:configMapDir = $agConfig.AgDirectories["AgConfigMapDir"] $global:AgDeploymentFolder = $AgConfig.AgDirectories["AgL1Files"] $global:AgPowerShellDir = $AgConfig.AgDirectories["AgPowerShellDir"] -$global:industry = $Env:industry +$global:AgLogsDir = $AgConfig.AgDirectories["AgLogsDir"] +$global:AgTestsDir = $AgConfig.AgDirectories["AgTestsDir"] +$global:scenario = $Env:scenario $global:websiteUrls = $AgConfig.URLs $global:githubAccount = $Env:githubAccount $global:githubBranch = $Env:githubBranch @@ -29,39 +31,66 @@ $global:adxClusterName = $Env:adxClusterName $global:namingGuid = $Env:namingGuid $global:adminPassword = $Env:adminPassword $global:customLocationRPOID = $Env:customLocationRPOID -$global:appUpstreamRepo = "https://github.com/microsoft/jumpstart-agora-apps" $global:appsRepo = "jumpstart-agora-apps" -$global:AKSEEPinnedSchemaVersion = $Env:AKSEEPinnedSchemaVersion -if ($industry -eq "retail") { +if ($scenario -eq "contoso_supermarket") { + $global:appUpstreamRepo = "https://github.com/microsoft/jumpstart-agora-apps" $global:githubUser = $Env:githubUser $global:githubPat = $Env:GITHUB_TOKEN - $global:acrName = $Env:acrName.ToLower() $global:cosmosDBName = $Env:cosmosDBName $global:cosmosDBEndpoint = $Env:cosmosDBEndpoint $global:gitHubAPIBaseUri = $websiteUrls["githubAPI"] $global:workflowStatus = "" $global:appClonedRepo = "https://github.com/$githubUser/jumpstart-agora-apps" -}elseif ($industry -eq "manufacturing") { +}elseif ($scenario -eq "contoso_motors") { + $global:appUpstreamRepo = "https://github.com/microsoft/jumpstart-agora-apps" $global:aioNamespace = "azure-iot-operations" $global:mqListenerService = "aio-mq-dmqtt-frontend" $global:mqttExplorerReleasesUrl = $websiteUrls["mqttExplorerReleases"] $global:stagingStorageAccountName = $Env:stagingStorageAccountName $global:aioStorageAccountName = $Env:aioStorageAccountName $global:spnObjectId = $Env:spnObjectId - $global:stcontainerName = $Env:stcontainerName +}elseif ($scenario -eq "contoso_hypermarket"){ + $global:appUpstreamRepo = "https://github.com/Azure/jumpstart-apps" + $global:tenantId = $Env:tenantId + $global:aioNamespace = "azure-iot-operations" + $global:mqListenerService = "aio-broker-insecure" + $global:mqttExplorerReleasesUrl = $websiteUrls["mqttExplorerReleases"] + $global:stagingStorageAccountName = $Env:stagingStorageAccountName + $global:aioStorageAccountName = $Env:aioStorageAccountName + $global:k3sArcDataClusterName = $Env:k3sArcDataClusterName + $global:k3sArcClusterName = $Env:k3sArcClusterName + $global:azureOpenAIModel = $Env:azureOpenAIModel + $global:openAIEndpoint = $Env:openAIEndpoint + $global:speachToTextEndpoint = $Env:speachToTextEndpoint + $global:openAIDeploymentName = $Env:openAIDeploymentName } ##################################################################### # Importing fuctions ##################################################################### Import-Module "$AgPowerShellDir\common.psm1" -Force -DisableNameChecking -Import-Module "$AgPowerShellDir\retail.psm1" -Force -DisableNameChecking -Import-Module "$AgPowerShellDir\manufacturing.psm1" -Force -DisableNameChecking +Import-Module "$AgPowerShellDir\contoso_supermarket.psm1" -Force -DisableNameChecking +Import-Module "$AgPowerShellDir\contoso_motors.psm1" -Force -DisableNameChecking +Import-Module "$AgPowerShellDir\contoso_hypermarket.psm1" -Force -DisableNameChecking -Start-Transcript -Path ($AgConfig.AgDirectories["AgLogsDir"] + "\AgLogonScript.log") -Write-Header "Executing Jumpstart Agora automation scripts" +Start-Transcript -Path ($AgLogsDir + "\AgLogonScript.log") +Write-Host "Executing Jumpstart Agora automation scripts" $startTime = Get-Date +# Remove registry keys that are used to automatically logon the user (only used for first-time setup) +$registryPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" +$keys = @("AutoAdminLogon", "DefaultUserName", "DefaultPassword") + +foreach ($key in $keys) { + try { + $property = Get-ItemProperty -Path $registryPath -Name $key -ErrorAction Stop + Remove-ItemProperty -Path $registryPath -Name $key + Write-Host "Removed registry key that are used to automatically logon the user: $key" + } catch { + Write-Verbose "Key $key does not exist." + } +} + # Disable Windows firewall Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False @@ -75,8 +104,12 @@ $global:Credentials = New-Object System.Management.Automation.PSCredential($AgCo # Setup Azure CLI ##################################################################### Write-Host "[$(Get-Date -Format t)] INFO: Configuring Azure CLI (Step 1/17)" -ForegroundColor DarkGreen -Write-Host "[$(Get-Date -Format t)] INFO: Logging into Az CLI using the service principal and secret provided at deployment" -ForegroundColor Gray -az login --service-principal --username $Env:spnClientID --password=$Env:spnClientSecret --tenant $Env:spnTenantId | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\AzCLI.log") +Write-Host "[$(Get-Date -Format t)] INFO: Logging into Az CLI" -ForegroundColor Gray +if($scenario -eq "contoso_hypermarket"){ + az login --identity | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\AzCLI.log") +}else{ + az login --service-principal --username $Env:spnClientID --password=$Env:spnClientSecret --tenant $Env:spnTenantId | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\AzCLI.log") +} az account set -s $subscriptionId Deploy-AzCLI @@ -96,16 +129,16 @@ Deploy-WindowsTools ##################################################################### # Configure Jumpstart Agora Apps repository ##################################################################### -if ($industry -eq "retail") { +if ($scenario -eq "contoso_supermarket") { Write-Host "INFO: Forking and preparing Apps repository locally (Step 4/17)" -ForegroundColor DarkGreen - SetupRetailRepo + SetupSupermarketRepo } ##################################################################### # Azure IoT Hub resources preparation ##################################################################### -if ($industry -eq "retail") { +if ($scenario -eq "contoso_supermarket") { Write-Host "[$(Get-Date -Format t)] INFO: Creating Azure IoT resources (Step 5/17)" -ForegroundColor DarkGreen Deploy-AzureIoTHub } @@ -113,16 +146,27 @@ if ($industry -eq "retail") { ##################################################################### # Configure L1 virtualization infrastructure ##################################################################### -Write-Host "[$(Get-Date -Format t)] INFO: Configuring L1 virtualization infrastructure (Step 6/17)" -ForegroundColor DarkGreen -Deploy-VirtualizationInfrastructure +if ($scenario -eq "contoso_supermarket" -or $scenario -eq "contoso_motors") { + Write-Host "[$(Get-Date -Format t)] INFO: Configuring L1 virtualization infrastructure (Step 6/17)" -ForegroundColor DarkGreen + Deploy-VirtualizationInfrastructure +} ##################################################################### # Setup Azure Container registry on cloud AKS staging environment ##################################################################### -if ($industry -eq "retail") { +if ($scenario -eq "contoso_supermarket") { Deploy-AzContainerRegistry } +##################################################################### +# Get clusters config files +##################################################################### +if($scenario -eq "contoso_hypermarket"){ + Get-K3sConfigFile + Merge-K3sConfigFiles + Set-K3sClusters +} + ##################################################################### # Creating Kubernetes namespaces on clusters ##################################################################### @@ -132,19 +176,25 @@ Deploy-ClusterNamespaces ##################################################################### # Setup Azure Container registry pull secret on clusters ##################################################################### -Write-Host "[$(Get-Date -Format t)] INFO: Configuring secrets on clusters (Step 9/17)" -ForegroundColor DarkGreen -Deploy-ClusterSecrets +if($scenario -ne "contoso_hypermarket"){ + Write-Host "[$(Get-Date -Format t)] INFO: Configuring secrets on clusters (Step 9/17)" -ForegroundColor DarkGreen + Deploy-ClusterSecrets +} ##################################################################### # Cache contoso-supermarket images on all clusters ##################################################################### -Deploy-K8sImagesCache +if ($scenario -eq "contoso_supermarket") { + Deploy-K8sImagesCache +} ##################################################################### # Connect the AKS Edge Essentials clusters and hosts to Azure Arc ##################################################################### -Write-Host "[$(Get-Date -Format t)] INFO: Connecting AKS Edge clusters to Azure with Azure Arc (Step 10/17)" -ForegroundColor DarkGreen -Deploy-AzArcK8s +if($scenario -eq "contoso_supermarket" -or $scenario -eq "contoso_motors"){ + Write-Host "[$(Get-Date -Format t)] INFO: Connecting AKS Edge clusters to Azure with Azure Arc (Step 10/17)" -ForegroundColor DarkGreen + Deploy-AzArcK8sAKSEE +} ##################################################################### # Installing flux extension on clusters @@ -155,7 +205,7 @@ Deploy-ClusterFluxExtension ##################################################################### # Deploying nginx on AKS cluster ##################################################################### -if ($industry -eq "retail") { +if ($scenario -eq "contoso_supermarket") { Write-Host "[$(Get-Date -Format t)] INFO: Deploying nginx on AKS cluster (Step 12/17)" -ForegroundColor DarkGreen kubectx $AgConfig.SiteConfig.Staging.FriendlyName.ToLower() | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Nginx.log") helm repo add $AgConfig.nginx.RepoName $AgConfig.nginx.RepoURL | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Nginx.log") @@ -166,52 +216,85 @@ if ($industry -eq "retail") { --namespace $AgConfig.nginx.Namespace ` --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Nginx.log") } + +############################################################## +# Deploy Kubernetes Prometheus Stack for Observability +############################################################## +Deploy-Prometheus -AgConfig $AgConfig + ##################################################################### # Configuring applications on the clusters using GitOps ##################################################################### -if ($industry -eq "retail") { +if ($scenario -eq "contoso_supermarket") { Write-Host "[$(Get-Date -Format t)] INFO: Configuring GitOps (Step 13/17)" -ForegroundColor DarkGreen - Deploy-RetailConfigs + Deploy-SupermarketConfigs } -if ($industry -eq "manufacturing") { +if ($scenario -eq "contoso_motors") { Update-AzureIoTOpsExtension Deploy-AIO - Deploy-ManufacturingConfigs + Deploy-MotorsConfigs + $mqttIpArray=Set-MQTTIpAddress + Deploy-MQTTExplorer -mqttIpArray $mqttIpArray +}elseif($scenario -eq "contoso_hypermarket"){ + Deploy-AIO-M3 $mqttIpArray=Set-MQTTIpAddress - #Deploy-MQTTSimulator -mqttIpArray $mqttIpArray # this is now being done via helm Deploy-MQTTExplorer -mqttIpArray $mqttIpArray + Set-AIServiceSecrets + Set-EventHubSecrets + Set-SQLSecret + if ($Env:deployGPUNodes -eq "true") { + Set-GPUOperator + } + Deploy-HypermarketConfigs + Set-LoadBalancerBackendPools } -############################################################## -# Deploy Kubernetes Prometheus Stack for Observability -############################################################## -Deploy-Prometheus -AgConfig $AgConfig - ##################################################################### # Deploy Azure Workbook for Infrastructure Observability ##################################################################### -Deploy-Workbook "arc-inventory-workbook.bicep" +if($scenario -ne "contoso_hypermarket"){ + Deploy-Workbook "arc-inventory-workbook.bicep" +} ##################################################################### # Deploy Azure Workbook for OS Performance ##################################################################### -Deploy-Workbook "arc-osperformance-workbook.bicep" +if($scenario -ne "contoso_hypermarket"){ + Deploy-Workbook "arc-osperformance-workbook.bicep" +} ##################################################################### # Deploy Azure Data Explorer Dashboard Reports ##################################################################### -if($industry -eq "manufacturing"){ +if($scenario -eq "contoso_motors"){ Deploy-ADXDashboardReports } +##################################################################### +# Deploy Microsoft Fabric +##################################################################### +if($scenario -eq "contoso_hypermarket"){ + Set-MicrosoftFabric +} + ############################################################## -# Creating bookmarks +# Creating bookmarks and setting merged kubeconfigs ############################################################## Write-Host "[$(Get-Date -Format t)] INFO: Creating Microsoft Edge Bookmarks in Favorites Bar (Step 15/17)" -ForegroundColor DarkGreen -if($industry -eq "retail"){ - Deploy-RetailBookmarks -}else{ - Deploy-ManufacturingBookmarks +if($scenario -eq "contoso_supermarket"){ + Deploy-SupermarketBookmarks +}elseif($scenario -eq "contoso_motors"){ + Deploy-MotorsBookmarks +}elseif($scenario -eq "contoso_hypermarket"){ + Deploy-HypermarketBookmarks +} + +############################################################## +# Creating database connections desktop shortcuts +############################################################## +Write-Host "[$(Get-Date -Format t)] INFO: Creating database connections desktop shortcuts (Step 16/17)" -ForegroundColor DarkGreen +if($scenario -eq "contoso_hypermarket"){ + Set-DatabaseConnectionsShortcuts } ############################################################## @@ -219,10 +302,13 @@ if($industry -eq "retail"){ ############################################################## Write-Host "[$(Get-Date -Format t)] INFO: Cleaning up scripts and uploading logs (Step 17/17)" -ForegroundColor DarkGreen # Creating Hyper-V Manager desktop shortcut -Write-Host "[$(Get-Date -Format t)] INFO: Creating Hyper-V desktop shortcut." -ForegroundColor Gray -Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Hyper-V Manager.lnk" -Destination "C:\Users\All Users\Desktop" -Force -if($industry -eq "retail"){ +if($scenario -ne "contoso_hypermarket") { + Write-Host "[$(Get-Date -Format t)] INFO: Creating Hyper-V desktop shortcut." -ForegroundColor Gray + Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Hyper-V Manager.lnk" -Destination "C:\Users\All Users\Desktop" -Force +} + +if($scenario -eq "contoso_supermarket"){ Write-Host "[$(Get-Date -Format t)] INFO: Cleaning up images-cache job" -ForegroundColor Gray while ($(Get-Job -Name images-cache-cleanup).State -eq 'Running') { Write-Host "[$(Get-Date -Format t)] INFO: Waiting for images-cache job to complete on all clusters...waiting 60 seconds" -ForegroundColor Gray @@ -232,48 +318,53 @@ if($industry -eq "retail"){ Get-Job -name images-cache-cleanup | Remove-Job } +# Create desktop shortcut for Logs-folder +$WshShell = New-Object -comObject WScript.Shell +$LogsPath = "C:\Ag\Logs" +$Shortcut = $WshShell.CreateShortcut("$Env:USERPROFILE\Desktop\Logs.lnk") +$Shortcut.TargetPath = $LogsPath +$shortcut.WindowStyle = 3 +$shortcut.Save() + +# Configure Windows Terminal as the default terminal application +$registryPath = "HKCU:\Console\%%Startup" + +if (Test-Path $registryPath) { + Set-ItemProperty -Path $registryPath -Name "DelegationConsole" -Value "{2EACA947-7F5F-4CFA-BA87-8F7FBEEFBE69}" + Set-ItemProperty -Path $registryPath -Name "DelegationTerminal" -Value "{E12CFF52-A866-4C77-9A90-F570A7AA2C6B}" +} else { + New-Item -Path $registryPath -Force | Out-Null + Set-ItemProperty -Path $registryPath -Name "DelegationConsole" -Value "{2EACA947-7F5F-4CFA-BA87-8F7FBEEFBE69}" + Set-ItemProperty -Path $registryPath -Name "DelegationTerminal" -Value "{E12CFF52-A866-4C77-9A90-F570A7AA2C6B}" +} + # Removing the LogonScript Scheduled Task Write-Host "[$(Get-Date -Format t)] INFO: Removing scheduled logon task so it won't run on next login." -ForegroundColor Gray Unregister-ScheduledTask -TaskName "AgLogonScript" -Confirm:$false -# Executing the deployment logs bundle PowerShell script in a new window -Write-Host "[$(Get-Date -Format t)] INFO: Uploading Log Bundle." -ForegroundColor Gray -$Env:AgLogsDir = $AgConfig.AgDirectories["AgLogsDir"] -Invoke-Expression 'cmd /c start Powershell -Command { -$RandomString = -join ((48..57) + (97..122) | Get-Random -Count 6 | % {[char]$_}) -Write-Host "Sleeping for 5 seconds before creating deployment logs bundle..." -Start-Sleep -Seconds 5 -Write-Host "`n" Write-Host "Creating deployment logs bundle" -7z a $Env:AgLogsDir\LogsBundle-"$RandomString".zip $Env:AgLogsDir\*.log -}' + +$RandomString = -join ((48..57) + (97..122) | Get-Random -Count 6 | % {[char]$_}) +$LogsBundleTempDirectory = "$Env:windir\TEMP\LogsBundle-$RandomString" +$null = New-Item -Path $LogsBundleTempDirectory -ItemType Directory -Force + +#required to avoid "file is being used by another process" error when compressing the logs +Copy-Item -Path "$($AgConfig.AgDirectories["AgDir"])\Logs\*.log" -Destination $LogsBundleTempDirectory -Force -PassThru +Compress-Archive -Path "$LogsBundleTempDirectory\*.log" -DestinationPath "$($AgConfig.AgDirectories["AgDir"])\Logs\LogsBundle-$RandomString.zip" -PassThru Write-Host "[$(Get-Date -Format t)] INFO: Changing Wallpaper" -ForegroundColor Gray + +# bmp file is required for BGInfo $imgPath = $AgConfig.AgDirectories["AgDir"] + "\wallpaper.png" -$code = @' -using System.Runtime.InteropServices; -namespace Win32{ +$targetImgPath = $($imgPath -replace 'png','bmp') +Convert-JSImageToBitMap -SourceFilePath $imgPath -DestinationFilePath $targetImgPath - public class Wallpaper{ - [DllImport("user32.dll", CharSet=CharSet.Auto)] - static extern int SystemParametersInfo (int uAction , int uParam , string lpvParam , int fuWinIni) ; +Set-JSDesktopBackground -ImagePath $targetImgPath - public static void SetWallpaper(string thePath){ - SystemParametersInfo(20,0,thePath,3); - } - } -} -'@ -Add-Type $code -[Win32.Wallpaper]::SetWallpaper($imgPath) +Write-Host "Running tests to verify infrastructure" -# Kill the open PowerShell monitoring kubectl get pods -# if ($industry -eq "manufacturing") { -# foreach ($shell in $kubectlMonShells) { -# Stop-Process -Id $shell.Id -# } -# } +& "$AgTestsDir\Invoke-Test.ps1" $endTime = Get-Date $timeSpan = New-TimeSpan -Start $starttime -End $endtime @@ -281,4 +372,4 @@ Write-Host Write-Host "[$(Get-Date -Format t)] INFO: Deployment is complete. Deployment time was $($timeSpan.Hours) hour and $($timeSpan.Minutes) minutes. Enjoy the Agora experience!" -ForegroundColor Green Write-Host -Stop-Transcript \ No newline at end of file +Stop-Transcript diff --git a/azure_jumpstart_ag/artifacts/PowerShell/Bootstrap.ps1 b/azure_jumpstart_ag/artifacts/PowerShell/Bootstrap.ps1 index 7f10b42be4..e28124d2db 100644 --- a/azure_jumpstart_ag/artifacts/PowerShell/Bootstrap.ps1 +++ b/azure_jumpstart_ag/artifacts/PowerShell/Bootstrap.ps1 @@ -6,6 +6,7 @@ param ( [string]$spnObjectId, [string]$spnTenantId, [string]$spnAuthority, + [string]$tenantId, [string]$subscriptionId, [string]$resourceGroup, [string]$azureLocation, @@ -13,7 +14,6 @@ param ( [string]$workspaceName, [string]$aksStagingClusterName, [string]$iotHubHostName, - [string]$acrName, [string]$cosmosDBName, [string]$cosmosDBEndpoint, [string]$templateBaseUrl, @@ -24,11 +24,16 @@ param ( [string]$githubUser, [string]$adxClusterName, [string]$namingGuid, - [string]$industry, + [string]$scenario, [string]$customLocationRPOID, [string]$aioStorageAccountName, - [string]$stcontainerName, - [string]$AKSEEPinnedSchemaVersion + [string]$k3sArcClusterName, + [string]$k3sArcDataClusterName, + [string]$vmAutologon, + [string]$openAIEndpoint, + [string]$speachToTextEndpoint, + [object]$azureOpenAIModel, + [string]$openAIDeploymentName ) ############################################################## @@ -44,6 +49,7 @@ param ( [System.Environment]::SetEnvironmentVariable('SPN_CLIENT_ID', $spnClientId, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('SPN_CLIENT_SECRET', $spnClientSecret, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('SPN_TENANT_ID', $spnTenantId, [System.EnvironmentVariableTarget]::Machine) +[System.Environment]::SetEnvironmentVariable('tenantId', $tenantId, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('SPN_AUTHORITY', $spnAuthority, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('resourceGroup', $resourceGroup, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('subscriptionId', $subscriptionId, [System.EnvironmentVariableTarget]::Machine) @@ -52,7 +58,6 @@ param ( [System.Environment]::SetEnvironmentVariable('workspaceName', $workspaceName, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('aksStagingClusterName', $aksStagingClusterName, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('iotHubHostName', $iotHubHostName, [System.EnvironmentVariableTarget]::Machine) -[System.Environment]::SetEnvironmentVariable('acrName', $acrName, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('cosmosDBName', $cosmosDBName, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('cosmosDBEndpoint', $cosmosDBEndpoint, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('templateBaseUrl', $templateBaseUrl, [System.EnvironmentVariableTarget]::Machine) @@ -63,11 +68,15 @@ param ( [System.Environment]::SetEnvironmentVariable('AgDir', "C:\Ag", [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('adxClusterName', $adxClusterName, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('namingGuid', $namingGuid, [System.EnvironmentVariableTarget]::Machine) -[System.Environment]::SetEnvironmentVariable('industry', $industry, [System.EnvironmentVariableTarget]::Machine) +[System.Environment]::SetEnvironmentVariable('scenario', $scenario, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('customLocationRPOID', $customLocationRPOID, [System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('aioStorageAccountName', $aioStorageAccountName, [System.EnvironmentVariableTarget]::Machine) -[System.Environment]::SetEnvironmentVariable('stcontainerName', $stcontainerName, [System.EnvironmentVariableTarget]::Machine) -[System.Environment]::SetEnvironmentVariable('AKSEEPinnedSchemaVersion', $AKSEEPinnedSchemaVersion, [System.EnvironmentVariableTarget]::Machine) +[System.Environment]::SetEnvironmentVariable('k3sArcClusterName', $k3sArcClusterName, [System.EnvironmentVariableTarget]::Machine) +[System.Environment]::SetEnvironmentVariable('k3sArcDataClusterName', $k3sArcDataClusterName, [System.EnvironmentVariableTarget]::Machine) +[System.Environment]::SetEnvironmentVariable('openAIEndpoint', $openAIEndpoint, [System.EnvironmentVariableTarget]::Machine) +[System.Environment]::SetEnvironmentVariable('speachToTextEndpoint', $speachToTextEndpoint, [System.EnvironmentVariableTarget]::Machine) +[System.Environment]::SetEnvironmentVariable('azureOpenAIModel', $azureOpenAIModel, [System.EnvironmentVariableTarget]::Machine) +[System.Environment]::SetEnvironmentVariable('openAIDeploymentName', $openAIDeploymentName, [System.EnvironmentVariableTarget]::Machine) $ErrorActionPreference = 'Continue' @@ -102,15 +111,33 @@ if (($rdpPort -ne $null) -and ($rdpPort -ne "") -and ($rdpPort -ne "3389")) { Write-Host "RDP port configuration complete." } +$adminPassword = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($adminPassword)) + +if ($vmAutologon -eq "true") { + + Write-Host "Configuring VM Autologon" + + Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" "AutoAdminLogon" "1" + Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" "DefaultUserName" $adminUsername + Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" "DefaultPassword" $adminPassword + if($flavor -eq "DataOps"){ + Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" "DefaultDomainName" "jumpstart.local" + } +} else { + + Write-Host "Not configuring VM Autologon" + +} ############################################################## # Download configuration data file and declaring directories ############################################################## $ConfigurationDataFile = "C:\Temp\AgConfig.psd1" -switch ($industry) { - "retail" { Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/AgConfig-retail.psd1") -OutFile $ConfigurationDataFile } - "manufacturing" {Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/AgConfig-manufacturing.psd1") -OutFile $ConfigurationDataFile} +switch ($scenario) { + "contoso_supermarket" { Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/AgConfig-contoso-supermarket.psd1") -OutFile $ConfigurationDataFile } + "contoso_motors" {Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/AgConfig-contoso-motors.psd1") -OutFile $ConfigurationDataFile} + "contoso_hypermarket" {Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/AgConfig-contoso-hypermarket.psd1") -OutFile $ConfigurationDataFile} } $AgConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile @@ -219,8 +246,32 @@ foreach ($url in $websiteUrls.Values) { # Copy PowerShell Profile and Reload ############################################################## Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/PSProfile.ps1") -OutFile $PsHome\Profile.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/PSProfile.ps1") -OutFile "$AgPowerShellDir\Profile.ps1" .$PsHome\Profile.ps1 +############################################################## +# Installing PowerShell 7 +############################################################## +$ProgressPreference = 'SilentlyContinue' +$url = "https://github.com/PowerShell/PowerShell/releases/latest" +$latestVersion = (Invoke-WebRequest -UseBasicParsing -Uri $url).Content | Select-String -Pattern "v[0-9]+\.[0-9]+\.[0-9]+" | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value +$downloadUrl = "https://github.com/PowerShell/PowerShell/releases/download/$latestVersion/PowerShell-$($latestVersion.Substring(1,5))-win-x64.msi" +Invoke-WebRequest -UseBasicParsing -Uri $downloadUrl -OutFile .\PowerShell7.msi +Start-Process msiexec.exe -Wait -ArgumentList '/I PowerShell7.msi /quiet ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 ENABLE_PSREMOTING=1 REGISTER_MANIFEST=1 USE_MU=1 ENABLE_MU=1 ADD_PATH=1' +Remove-Item .\PowerShell7.msi + +Copy-Item $PsHome\Profile.ps1 -Destination "C:\Program Files\PowerShell\7\" + +# Installing PowerShell Modules +Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force + +Install-Module -Name Microsoft.PowerShell.PSResourceGet -Force +$modules = @("Az", "Az.ConnectedMachine", "Az.ConnectedKubernetes", "Az.CustomLocation", "Azure.Arc.Jumpstart.Common", "Microsoft.PowerShell.SecretManagement", "Pester") + +foreach ($module in $modules) { + Install-PSResource -Name $module -Scope AllUsers -Quiet -AcceptLicense -TrustRepository +} + ############################################################## # Get latest Grafana OSS release ############################################################## @@ -234,8 +285,9 @@ Copy-Item $ConfigurationDataFile "$AgPowerShellDir\AgConfig.psd1" -Force Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/AgLogonScript.ps1") -OutFile "$AgPowerShellDir\AgLogonScript.ps1" Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Modules/common.psm1") -OutFile "$AgPowerShellDir\common.psm1" -Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Modules/retail.psm1") -OutFile "$AgPowerShellDir\retail.psm1" -Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Modules/manufacturing.psm1") -OutFile "$AgPowerShellDir\manufacturing.psm1" +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Modules/contoso_supermarket.psm1") -OutFile "$AgPowerShellDir\contoso_supermarket.psm1" +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Modules/contoso_motors.psm1") -OutFile "$AgPowerShellDir\contoso_motors.psm1" +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Modules/contoso_hypermarket.psm1") -OutFile "$AgPowerShellDir\contoso_hypermarket.psm1" Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/DockerDesktopSettings.json") -OutFile "$AgToolsDir\settings.json" Invoke-WebRequest "https://raw.githubusercontent.com/Azure/arc_jumpstart_docs/main/img/wallpaper/agora_wallpaper_dark.png" -OutFile $AgDirectory\wallpaper.png Invoke-WebRequest ($templateBaseUrl + "artifacts/monitoring/grafana-node-exporter-full.json") -OutFile "$AgMonitoringDir\grafana-node-exporter-full.json" @@ -249,75 +301,44 @@ Invoke-WebRequest ($templateBaseUrl + "artifacts/icons/contoso.svg") -OutFile $A Invoke-WebRequest ($templateBaseUrl + "artifacts/icons/contoso-motors.png") -OutFile $AgIconsDir\contoso-motors.png Invoke-WebRequest ($templateBaseUrl + "artifacts/icons/contoso-motors.svg") -OutFile $AgIconsDir\contoso-motors.svg Invoke-WebRequest ($templateBaseUrl + "artifacts/L1Files/config.json") -OutFile $AgDeploymentFolder\config.json - -if($industry -eq "retail"){ - Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/Bookmarks-retail") -OutFile "$AgToolsDir\Bookmarks" +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Winget.ps1") -OutFile "$AgPowerShellDir\Winget.ps1" +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/tests/common.tests.ps1") -OutFile "$AgDirectory\tests\common.tests.ps1" +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/tests/k8s.tests.ps1") -OutFile "$AgDirectory\tests\k8s.tests.ps1" +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/tests/Invoke-Test.ps1") -OutFile "$AgDirectory\tests\Invoke-Test.ps1" +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/tests/ag-bginfo.bgi") -OutFile "$AgDirectory\tests\ag-bginfo.bgi" + +if($scenario -eq "contoso_supermarket"){ + Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/Bookmarks-contoso-supermarket") -OutFile "$AgToolsDir\Bookmarks" Invoke-WebRequest ($templateBaseUrl + "artifacts/monitoring/grafana-freezer-monitoring.json") -OutFile "$AgMonitoringDir\grafana-freezer-monitoring.json" } -elseif ($industry -eq "manufacturing") { - Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/Bookmarks-manufacturing") -OutFile "$AgToolsDir\Bookmarks" +elseif ($scenario -eq "contoso_motors") { + Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/Bookmarks-contoso-motors") -OutFile "$AgToolsDir\Bookmarks" Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/mq_cloudConnector.yml") -OutFile "$AgToolsDir\mq_cloudConnector.yml" - Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/mqtt_explorer_settings.json") -OutFile "$AgToolsDir\mqtt_explorer_settings.json" + Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/mqtt_explorer_settings_motors.json") -OutFile "$AgToolsDir\mqtt_explorer_settings.json" +} +elseif ($scenario -eq "contoso_hypermarket") { + Invoke-WebRequest ($templateBaseUrl + "artifacts/kubernetes/K3s/longhorn.yaml") -OutFile "$AgToolsDir\longhorn.yaml" + Invoke-WebRequest ($templateBaseUrl + "artifacts/kubernetes/K3s/kubeVipRbac.yml") -OutFile "$AgToolsDir\kubeVipRbac.yml" + Invoke-WebRequest ($templateBaseUrl + "artifacts/kubernetes/K3s/kubeVipDaemon.yml") -OutFile "$AgToolsDir\kubeVipDaemon.yml" + Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/Bookmarks-contoso-hypermarket") -OutFile "$AgToolsDir\Bookmarks" + #Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/mq_cloudConnector.yml") -OutFile "$AgToolsDir\mq_cloudConnector.yml" + Invoke-WebRequest ($templateBaseUrl + "artifacts/settings/mqtt_explorer_settings_hypermarket.json") -OutFile "$AgToolsDir\mqtt_explorer_settings.json" + Invoke-WebRequest ($templateBaseUrl + "artifacts/monitoring/grafana-app-workloads.json") -OutFile "$AgMonitoringDir\grafana-app-workloads.json" + Invoke-WebRequest ($templateBaseUrl + "artifacts/monitoring/grafana-app-pods.json") -OutFile "$AgMonitoringDir\grafana-app-pods.json" + Invoke-WebRequest ($templateBaseUrl + "artifacts/monitoring/grafana-node-exporter-full-v2.json") -OutFile "$AgMonitoringDir\grafana-node-exporter-full-v2.json" + Invoke-WebRequest ($templateBaseUrl + "artifacts/monitoring/grafana-app-store-asset.json") -OutFile "$AgMonitoringDir\grafana-app-store-asset.json" + Invoke-WebRequest ($templateBaseUrl + "artifacts/monitoring/grafana-app-store-shoppers.json") -OutFile "$AgMonitoringDir\grafana-app-store-shoppers.json" + Invoke-WebRequest ($templateBaseUrl + "artifacts/monitoring/grafana-app-store-pos.json") -OutFile "$AgMonitoringDir\grafana-app-store-pos.json" + Invoke-WebRequest ($templateBaseUrl + "artifacts/icons/contoso-hypermarket.png") -OutFile $AgIconsDir\contoso-hypermarket.png + Invoke-WebRequest ($templateBaseUrl + "artifacts/icons/contoso-hypermarket.svg") -OutFile $AgIconsDir\contoso-hypermarket.svg } + BITSRequest -Params @{'Uri' = 'https://aka.ms/wslubuntu'; 'Filename' = "$AgToolsDir\Ubuntu.appx" } BITSRequest -Params @{'Uri' = $websiteUrls["wslStoreStorage"]; 'Filename' = "$AgToolsDir\wsl_update_x64.msi" } BITSRequest -Params @{'Uri' = $websiteUrls["docker"]; 'Filename' = "$AgToolsDir\DockerDesktopInstaller.exe" } BITSRequest -Params @{'Uri' = "https://dl.grafana.com/oss/release/grafana-$latestRelease.windows-amd64.msi"; 'Filename' = "$AgToolsDir\grafana-$latestRelease.windows-amd64.msi" } -############################################################## -# Install Chocolatey packages -############################################################## -$maxRetries = 3 -$retryDelay = 30 # seconds - -$retryCount = 0 -$success = $false - -while (-not $success -and $retryCount -lt $maxRetries) { - try { - Write-Header "Installing Chocolatey packages" - try { - choco config get cacheLocation - } - catch { - Write-Output "Chocolatey not detected, trying to install now" - Invoke-Expression ((New-Object System.Net.WebClient).DownloadString($AgConfig.URLs.chocoInstallScript)) - } - - Write-Host "Chocolatey packages specified" - - foreach ($app in $AgConfig.ChocolateyPackagesList) { - Write-Host "Installing $app" - & choco install $app /y -Force | Write-Output - } - - # If the command succeeds, set $success to $true to exit the loop - $success = $true - } - catch { - # If an exception occurs, increment the retry count - $retryCount++ - - # If the maximum number of retries is not reached yet, display an error message - if ($retryCount -lt $maxRetries) { - Write-Host "Attempt $retryCount failed. Retrying in $retryDelay seconds..." - Start-Sleep -Seconds $retryDelay - } - else { - Write-Host "All attempts failed. Exiting..." - exit 1 # Stop script execution if maximum retries reached - } - } -} - -############################################################## -# Install Azure CLI (64-bit not available via Chocolatey) -############################################################## -$ProgressPreference = 'SilentlyContinue' -Invoke-WebRequest -Uri https://aka.ms/installazurecliwindowsx64 -OutFile .\AzureCLI.msi -Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet' -Remove-Item .\AzureCLI.msi ############################################################## # Create Docker Desktop group @@ -325,8 +346,6 @@ Remove-Item .\AzureCLI.msi New-LocalGroup -Name "docker-users" -Description "docker Users Group" Add-LocalGroupMember -Group "docker-users" -Member $adminUsername -New-Item -path alias:kubectl -value 'C:\ProgramData\chocolatey\lib\kubernetes-cli\tools\kubernetes\client\bin\kubectl.exe' - ############################################################## # Disable Network Profile prompt ############################################################## @@ -373,12 +392,15 @@ New-ItemProperty -Path $AgConfig.EdgeSettingRegistryPath -Name $Name -Value $AgC ############################################################## # Installing Posh-SSH PowerShell Module ############################################################## -Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force Install-Module -Name Posh-SSH -Force +$ScheduledTaskExecutable = "C:\Program Files\PowerShell\7\pwsh.exe" $Trigger = New-ScheduledTaskTrigger -AtLogOn -$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "$AgPowerShellDir\AgLogonScript.ps1" -Register-ScheduledTask -TaskName "AgLogonScript" -Trigger $Trigger -User $adminUsername -Action $Action -RunLevel "Highest" -Force +$Action = New-ScheduledTaskAction -Execute "${ScheduledTaskExecutable}" -Argument $AgPowerShellDir\WinGet.ps1 +Register-ScheduledTask -TaskName "WinGetLogonScript" -Trigger $Trigger -User $adminUsername -Action $Action -RunLevel "Highest" -Force + +$Action = New-ScheduledTaskAction -Execute "${ScheduledTaskExecutable}" -Argument "$AgPowerShellDir\AgLogonScript.ps1" +Register-ScheduledTask -TaskName "AgLogonScript" -User $adminUsername -Action $Action -RunLevel "Highest" -Force ############################################################## # Disabling Windows Server Manager Scheduled Task @@ -388,11 +410,30 @@ Get-ScheduledTask -TaskName ServerManager | Disable-ScheduledTask ############################################################## # Install Hyper-V, WSL and reboot ############################################################## -Write-Header "Installing Hyper-V" -Enable-WindowsOptionalFeature -Online -FeatureName Containers -All -NoRestart -Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform -NoRestart -Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux -NoRestart -Install-WindowsFeature -Name Hyper-V -IncludeAllSubFeature -IncludeManagementTools -Restart +if($scenario -eq "contoso_supermarket" -or $scenario -eq "contoso_motors"){ + Write-Header "Installing Hyper-V" + Enable-WindowsOptionalFeature -Online -FeatureName Containers -All -NoRestart + Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform -NoRestart + Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux -NoRestart + Install-WindowsFeature -Name Hyper-V -IncludeAllSubFeature -IncludeManagementTools -Restart +}else{ + Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux -NoRestart +} + +# Restart machine to initiate VM autologon +$action = New-ScheduledTaskAction -Execute 'PowerShell.exe' -Argument '-Command "Restart-Computer -Force"' +$trigger = New-ScheduledTaskTrigger -Once -At ((Get-Date).AddSeconds(10)) +$taskName = "Restart-Computer-Delayed" + +# Define the restart action and schedule it to run after 10 seconds +$action = New-ScheduledTaskAction -Execute 'PowerShell.exe' -Argument '-Command "Restart-Computer -Force"' +$trigger = New-ScheduledTaskTrigger -Once -At ((Get-Date).AddSeconds(10)) + +# Configure the task to run with highest privileges and use the current user's credentials +$principal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest + +Register-ScheduledTask -Action $action -Trigger $trigger -TaskName $taskName -Principal $principal -Description "Restart computer after script exits" + Stop-Transcript diff --git a/azure_jumpstart_ag/artifacts/PowerShell/Modules/common.psm1 b/azure_jumpstart_ag/artifacts/PowerShell/Modules/common.psm1 index 6e6cfb5531..57d583762d 100644 --- a/azure_jumpstart_ag/artifacts/PowerShell/Modules/common.psm1 +++ b/azure_jumpstart_ag/artifacts/PowerShell/Modules/common.psm1 @@ -32,11 +32,17 @@ function Deploy-AzCLI { } function Deploy-AzPowerShell { - $azurePassword = ConvertTo-SecureString $Env:spnClientSecret -AsPlainText -Force - $psCred = New-Object System.Management.Automation.PSCredential($Env:spnClientID , $azurePassword) - Connect-AzAccount -Credential $psCred -TenantId $Env:spnTenantId -ServicePrincipal -Subscription $subscriptionId | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\AzPowerShell.log") + if($scenario -eq "contoso_hypermarket"){ + Connect-AzAccount -Identity -Tenant $Env:tenantId -Subscription $subscriptionId + } + else { + $azurePassword = ConvertTo-SecureString $Env:spnClientSecret -AsPlainText -Force + $psCred = New-Object System.Management.Automation.PSCredential($Env:spnClientID , $azurePassword) + Connect-AzAccount -Credential $psCred -TenantId $Env:spnTenantId -ServicePrincipal -Subscription $subscriptionId | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\AzPowerShell.log") + } + Set-AzContext -Subscription $subscriptionId - # Install PowerShell modules + # Making module install dynamic if ($AgConfig.PowerShellModules.Count -ne 0) { Write-Host "[$(Get-Date -Format t)] INFO: Installing PowerShell modules" -ForegroundColor Gray @@ -56,7 +62,7 @@ function Deploy-AzPowerShell { } # Register Azure providers - if ($AgConfig.AzureProviders.Count -ne 0) { + if ($AgConfig.AzureProviders.Count -ne 0 -and $scenario -ne "contoso_hypermarket") { Write-Host "[$(Get-Date -Format t)] INFO: Registering Azure providers in the current subscription: " ($AgConfig.AzureProviders -join ', ') -ForegroundColor Gray foreach ($provider in $AgConfig.AzureProviders) { Register-AzResourceProvider -ProviderNamespace $provider | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\AzPowerShell.log") @@ -255,7 +261,7 @@ function Deploy-VirtualizationInfrastructure { # Create an array with VM names $VMnames = (Get-VM).Name - $sourcePath = "$PsHome\Profile.ps1" + $sourcePath = "$AgPowerShellDir\Profile.ps1" $destinationPath = "C:\Deployment\Profile.ps1" $maxRetries = 3 @@ -308,26 +314,24 @@ function Deploy-VirtualizationInfrastructure { } Write-Host "[$(Get-Date -Format t)] INFO: Fetching the latest two AKS Edge Essentials releases." -ForegroundColor Gray + $latestReleaseTag = (Invoke-WebRequest $websiteUrls["aksEEReleases"] | ConvertFrom-Json)[0].tag_name + $beforeLatestReleaseTag = (Invoke-WebRequest $websiteUrls["aksEEReleases"] | ConvertFrom-Json)[1].tag_name + $AKSEEReleasesTags = ($latestReleaseTag, $beforeLatestReleaseTag) $AKSEESchemaVersions = @() - if($AKSEEPinnedSchemaVersion -eq "useLatest"){ - $latestReleaseTag = (Invoke-WebRequest $websiteUrls["aksEEReleases"] | ConvertFrom-Json)[0].tag_name - $beforeLatestReleaseTag = (Invoke-WebRequest $websiteUrls["aksEEReleases"] | ConvertFrom-Json)[1].tag_name - $AKSEEReleasesTags = ($latestReleaseTag, $beforeLatestReleaseTag) - - for ($i = 0; $i -lt $AKSEEReleasesTags.Count; $i++) { - $releaseTag = (Invoke-WebRequest $websiteUrls["aksEEReleases"] | ConvertFrom-Json)[$i].tag_name - $AKSEEReleaseDownloadUrl = "https://github.com/Azure/AKS-Edge/archive/refs/tags/$releaseTag.zip" - $output = Join-Path $AgToolsDir "$releaseTag.zip" - Invoke-WebRequest $AKSEEReleaseDownloadUrl -OutFile $output - Expand-Archive $output -DestinationPath $AgToolsDir -Force - $AKSEEReleaseConfigFilePath = "$AgToolsDir\AKS-Edge-$releaseTag\tools\aksedge-config.json" - $jsonContent = Get-Content -Raw -Path $AKSEEReleaseConfigFilePath | ConvertFrom-Json - $schemaVersion = $jsonContent.SchemaVersion - $AKSEESchemaVersions += $schemaVersion - # Clean up the downloaded release files - Remove-Item -Path $output -Force - Remove-Item -Path "$AgToolsDir\AKS-Edge-$releaseTag" -Force -Recurse - } + + for ($i = 0; $i -lt $AKSEEReleasesTags.Count; $i++) { + $releaseTag = (Invoke-WebRequest $websiteUrls["aksEEReleases"] | ConvertFrom-Json)[$i].tag_name + $AKSEEReleaseDownloadUrl = "https://github.com/Azure/AKS-Edge/archive/refs/tags/$releaseTag.zip" + $output = Join-Path $AgToolsDir "$releaseTag.zip" + Invoke-WebRequest $AKSEEReleaseDownloadUrl -OutFile $output + Expand-Archive $output -DestinationPath $AgToolsDir -Force + $AKSEEReleaseConfigFilePath = "$AgToolsDir\AKS-Edge-$releaseTag\tools\aksedge-config.json" + $jsonContent = Get-Content -Raw -Path $AKSEEReleaseConfigFilePath | ConvertFrom-Json + $schemaVersion = $jsonContent.SchemaVersion + $AKSEESchemaVersions += $schemaVersion + # Clean up the downloaded release files + Remove-Item -Path $output -Force + Remove-Item -Path "$AgToolsDir\AKS-Edge-$releaseTag" -Force -Recurse } Invoke-Command -VMName $VMnames -Credential $Credentials -ScriptBlock { @@ -360,7 +364,6 @@ function Deploy-VirtualizationInfrastructure { $AgConfig = $using:AgConfig $AgToolsDir = $using:AgToolsDir $websiteUrls = $using:websiteUrls - $AKSEEPinnedSchemaVersion = $using:AKSEEPinnedSchemaVersion ########################################## # Deploying AKS Edge Essentials clusters @@ -414,15 +417,12 @@ function Deploy-VirtualizationInfrastructure { # Fetch schemaVersion release from the AgConfig file $AKSEESchemaVersionUseLatest = $AgConfig.SiteConfig[$Env:COMPUTERNAME].AKSEEReleaseUseLatest - if ($AKSEESchemaVersionUseLatest -and $AKSEEPinnedSchemaVersion -eq "useLatest") { + if ($AKSEESchemaVersionUseLatest) { $SchemaVersion = $using:AKSEESchemaVersions[0] } - elseif (!$AKSEESchemaVersionUseLatest -and $AKSEEPinnedSchemaVersion -eq "useLatest") { + else { $SchemaVersion = $using:AKSEESchemaVersions[1] } - elseif ($AKSEEPinnedSchemaVersion -ne "useLatest") { - $SchemaVersion = $AKSEEPinnedSchemaVersion - } $replacementParams = @{ "SchemaVersion-null" = $SchemaVersion @@ -506,10 +506,10 @@ function Deploy-VirtualizationInfrastructure { ##################################################################### Write-Host "[$(Get-Date -Format t)] INFO: All three kubeconfig files are present. Merging kubeconfig files for use with kubectx." -ForegroundColor Gray $kubeconfigpath = "" - foreach ($VMName in $VMNames) { + foreach ($VMName in $VMNames) { # Create a kubeconfig path for each VM $kubeconfigpath = $kubeconfigpath + "$Env:USERPROFILE\.kube\config-" + $VMName.ToLower() + ";" } - $Env:KUBECONFIG = $kubeconfigpath + $Env:KUBECONFIG = $kubeconfigpath # Set the KUBECONFIG environment variable to the merged kubeconfig path kubectl config view --merge --flatten > "$Env:USERPROFILE\.kube\config-raw" | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\L1AKSInfra.log") kubectl config get-clusters --kubeconfig="$Env:USERPROFILE\.kube\config-raw" | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\L1AKSInfra.log") Rename-Item -Path "$Env:USERPROFILE\.kube\config-raw" -NewName "$Env:USERPROFILE\.kube\config" @@ -529,7 +529,12 @@ function Deploy-VirtualizationInfrastructure { } function Deploy-AzContainerRegistry { - az login --service-principal --username $Env:spnClientID --password=$Env:spnClientSecret --tenant $Env:spnTenantId | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\AzCLI.log") + if($scenario -eq "contoso_hypermarket"){ + az login --identity + } + else { + az login --service-principal --username $Env:spnClientID --password=$Env:spnClientSecret --tenant $Env:spnTenantId | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\AzCLI.log") + } az account set -s $Env:subscriptionId az aks get-credentials --resource-group $Env:resourceGroup --name $Env:aksStagingClusterName --admin | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\ClusterSecrets.log") kubectx staging="$Env:aksStagingClusterName-admin" | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\ClusterSecrets.log") @@ -554,7 +559,7 @@ function Deploy-ClusterSecrets { foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { $clusterName = $cluster.Name.ToLower() foreach ($namespace in $AgConfig.Namespaces) { - if ($namespace -eq "contoso-supermarket" -or $namespace -eq "images-cache") { + if ($namespace -eq "contoso-supermarket" -or $namespace -eq "images-cache" -or $namespace -eq "contoso-hypermarket") { Write-Host "[$(Get-Date -Format t)] INFO: Configuring Azure Container registry on $clusterName" kubectx $clusterName | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\ClusterSecrets.log") kubectl create secret docker-registry acr-secret ` @@ -569,7 +574,7 @@ function Deploy-ClusterSecrets { ##################################################################### # Create secrets for GitHub actions ##################################################################### - if ($Env:industry -eq "retail") { + if ($Env:scenario -eq "contoso_supermarket") { Write-Host "[$(Get-Date -Format t)] INFO: Creating Kubernetes secrets" -ForegroundColor Gray $cosmosDBKey = $(az cosmosdb keys list --name $cosmosDBName --resource-group $resourceGroup --query primaryMasterKey --output tsv) foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { @@ -589,7 +594,7 @@ function Deploy-ClusterSecrets { } } -function Deploy-AzArcK8s { +function Deploy-AzArcK8sAKSEE { # Running pre-checks to ensure that the aksedge ConfigMap is present on all clusters $maxRetries = 5 $retryInterval = 30 # seconds @@ -625,6 +630,7 @@ function Deploy-AzArcK8s { $tenantId = $Env:spnTenantId $location = $Env:azureLocation $resourceGroup = $Env:resourceGroup + $subscriptionId = $Env:subscriptionId Invoke-Command -VMName $VM -Credential $Credentials -ScriptBlock { # Install prerequisites @@ -638,9 +644,13 @@ function Deploy-AzArcK8s { Install-Module Az.ConnectedMachine -Force -AllowClobber -ErrorAction Stop # Connect servers to Arc - $azurePassword = ConvertTo-SecureString $using:secret -AsPlainText -Force - $psCred = New-Object System.Management.Automation.PSCredential($using:clientId, $azurePassword) - Connect-AzAccount -Credential $psCred -TenantId $using:tenantId -ServicePrincipal -Subscription $using:subscriptionId + if($scenario -eq "contoso_hypermarket"){ + Connect-AzAccount -Identity -Tenant $using:tenantId-Subscription $subscriptionId + }else{ + $azurePassword = ConvertTo-SecureString $using:secret -AsPlainText -Force + $psCred = New-Object System.Management.Automation.PSCredential($using:clientId, $azurePassword) + Connect-AzAccount -Credential $psCred -TenantId $using:tenantId -ServicePrincipal -Subscription $using:subscriptionId + } Write-Host "[$(Get-Date -Format t)] INFO: Arc-enabling $hostname server." -ForegroundColor Gray Redo-Command -ScriptBlock { Connect-AzConnectedMachine -ResourceGroupName $using:resourceGroup -Name "Ag-$hostname-Host" -Location $using:location } @@ -696,7 +706,7 @@ function Deploy-AzArcK8s { function Deploy-ClusterFluxExtension { $resourceTypes = @($AgConfig.ArcK8sResourceType, $AgConfig.AksResourceType) - $resources = Get-AzResource -ResourceGroupName $Env:resourceGroup | Where-Object { $_.ResourceType -in $resourceTypes } + $resources = Get-AzResource -ResourceGroupName $resourceGroup | Where-Object { $_.ResourceType -in $resourceTypes } $jobs = @() foreach ($resource in $resources) { @@ -744,7 +754,13 @@ function Deploy-ClusterFluxExtension { } } - az login --service-principal --username $Env:spnClientID --password=$Env:spnClientSecret --tenant $Env:spnTenantId + if($using:scenario -eq "contoso_hypermarket"){ + az login --identity + } + else { + az login --service-principal --username $Env:spnClientID --password=$Env:spnClientSecret --tenant $Env:spnTenantId + } + az account set -s $Env:subscriptionId $extension = az k8s-extension list --cluster-name $resourceName --resource-group $Env:resourceGroup --cluster-type $ClusterType --output json | ConvertFrom-Json $extension = $extension | Where-Object extensionType -eq 'microsoft.flux' @@ -839,7 +855,7 @@ function Deploy-Prometheus { helm repo add prometheus-community $websiteUrls["prometheus"] | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Observability.log") helm repo update | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Observability.log") - if ($Env:industry -eq "retail") { + if ($Env:scenario -eq "contoso_supermarket") { # Update Grafana Icons Copy-Item -Path $AgIconsDir\contoso.png -Destination "C:\Program Files\GrafanaLabs\grafana\public\img" Copy-Item -Path $AgIconsDir\contoso.svg -Destination "C:\Program Files\GrafanaLabs\grafana\public\img\grafana_icon.svg" @@ -853,7 +869,7 @@ function Deploy-Prometheus { (Get-Content $_.FullName) -replace 'Welcome to Grafana', 'Welcome to Grafana for Contoso Supermarket Production' | Set-Content $_.FullName } } - elseif ($Env:industry -eq "manufacturing") { + elseif ($Env:scenario -eq "contoso_motors") { # Update Grafana Icons Copy-Item -Path $AgIconsDir\contoso-motors.png -Destination "C:\Program Files\GrafanaLabs\grafana\public\img" Copy-Item -Path $AgIconsDir\contoso-motors.svg -Destination "C:\Program Files\GrafanaLabs\grafana\public\img\grafana_icon.svg" @@ -867,6 +883,20 @@ function Deploy-Prometheus { (Get-Content $_.FullName) -replace 'Welcome to Grafana', 'Welcome to Grafana for Contoso Motors' | Set-Content $_.FullName } } + elseif ($Env:scenario -eq "contoso_hypermarket") { + # Update Grafana Icons + Copy-Item -Path $AgIconsDir\contoso-hypermarket.png -Destination "C:\Program Files\GrafanaLabs\grafana\public\img" + Copy-Item -Path $AgIconsDir\contoso-hypermarket.svg -Destination "C:\Program Files\GrafanaLabs\grafana\public\img\grafana_icon.svg" + + Get-ChildItem -Path 'C:\Program Files\GrafanaLabs\grafana\public\build\*.js' -Recurse -File | ForEach-Object { + (Get-Content $_.FullName) -replace 'className:u,src:"public/img/grafana_icon.svg"', 'className:u,src:"public/img/contoso-hypermarket.png"' | Set-Content $_.FullName + } + + # Reset Grafana UI + Get-ChildItem -Path 'C:\Program Files\GrafanaLabs\grafana\public\build\*.js' -Recurse -File | ForEach-Object { + (Get-Content $_.FullName) -replace 'Welcome to Grafana', 'Welcome to Grafana for Contoso Hypermarket' | Set-Content $_.FullName + } + } # Reset Grafana Password $Env:Path += ';C:\Program Files\GrafanaLabs\grafana\bin' @@ -946,7 +976,6 @@ function Deploy-Prometheus { $AgConfig.SiteConfig.GetEnumerator() | ForEach-Object { Write-Host "[$(Get-Date -Format t)] INFO: Deploying Kube Prometheus Stack for $($_.Value.FriendlyName) environment" -ForegroundColor Gray kubectx $_.Value.FriendlyName.ToLower() | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Observability.log") - # Wait for Kubernetes API server to become available $apiServer = kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' $apiServerAddress = $apiServer -replace '.*https://| .*$' @@ -1023,12 +1052,60 @@ function Deploy-Prometheus { } Write-Host "[$(Get-Date -Format t)] INFO: Importing dashboards for $($_.Value.FriendlyName) environment" -ForegroundColor Gray - # Add dashboards + # Deploying dashboards (one dashboard for each store) + if ($Env:scenario -ne "contoso_hypermarket") { + foreach ($dashboard in $observabilityDashboardstoImport) { + $grafanaDBPath = "$AgMonitoringDir\grafana-$dashboard.json" + # Replace the datasource + $replacementParams = @{ + "\$\{DS_PROMETHEUS}" = $_.Value.GrafanaDataSource + } + $content = Get-Content $grafanaDBPath + foreach ($key in $replacementParams.Keys) { + $content = $content -replace $key, $replacementParams[$key] + } + # Set dashboard JSON + $dashboardObject = $content | ConvertFrom-Json + # Best practice is to generate a random UID, such as a GUID + $dashboardObject.uid = [guid]::NewGuid().ToString() + + # Need to set this to null to let Grafana generate a new ID + $dashboardObject.id = $null + # # Set dashboard title + $dashboardObject.title = $_.Value.FriendlyName + ' - ' + $dashboardObject.title + # Request body with dashboard to add + $grafanaDBBody = @{ + dashboard = $dashboardObject + overwrite = $true + } | ConvertTo-Json -Depth 10 + + if ($_.Value.IsProduction) { + # Set Grafana Dashboard endpoint + $grafanaDBURI = $AgConfig.Monitoring["ProdURL"] + "/api/dashboards/db" + $grafanaDBStarURI = $AgConfig.Monitoring["ProdURL"] + "/api/user/stars/dashboard" + } + else { + # Set Grafana Dashboard endpoint + $grafanaDBURI = "http://$monitorLBIP/api/dashboards/db" + $grafanaDBStarURI = "http://$monitorLBIP/api/user/stars/dashboard" + } + + # Make HTTP request to the API + $dashboardID = (Invoke-RestMethod -Method Post -Uri $grafanaDBURI -Headers $adminHeaders -Body $grafanaDBBody).id + + Invoke-RestMethod -Method Post -Uri "$grafanaDBStarURI/$dashboardID" -Headers $userHeaders | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Observability.log") + + } + } + } + + # Deploying dashboard for Contoso Hypermarket (One dashboard for all stores) + if ($Env:scenario -eq "contoso_hypermarket") { foreach ($dashboard in $observabilityDashboardstoImport) { $grafanaDBPath = "$AgMonitoringDir\grafana-$dashboard.json" # Replace the datasource $replacementParams = @{ - "\$\{DS_PROMETHEUS}" = $_.Value.GrafanaDataSource + "\$\{DS_PROMETHEUS}" = "prometheus" } $content = Get-Content $grafanaDBPath foreach ($key in $replacementParams.Keys) { @@ -1036,29 +1113,24 @@ function Deploy-Prometheus { } # Set dashboard JSON $dashboardObject = $content | ConvertFrom-Json - # Best practice is to generate a random UID, such as a GUID - $dashboardObject.uid = [guid]::NewGuid().ToString() + + # Set Dashboard UID for parent dashboards + if ($dashboard -notlike '*app-pods*') { + # Best practice is to generate a random UID, such as a GUID + $dashboardObject.uid = [guid]::NewGuid().ToString() + } # Need to set this to null to let Grafana generate a new ID $dashboardObject.id = $null - # Set dashboard title - $dashboardObject.title = $_.Value.FriendlyName + ' - ' + $dashboardObject.title # Request body with dashboard to add $grafanaDBBody = @{ dashboard = $dashboardObject overwrite = $true - } | ConvertTo-Json -Depth 8 + } | ConvertTo-Json -Depth 10 - if ($_.Value.IsProduction) { - # Set Grafana Dashboard endpoint - $grafanaDBURI = $AgConfig.Monitoring["ProdURL"] + "/api/dashboards/db" - $grafanaDBStarURI = $AgConfig.Monitoring["ProdURL"] + "/api/user/stars/dashboard" - } - else { - # Set Grafana Dashboard endpoint - $grafanaDBURI = "http://$monitorLBIP/api/dashboards/db" - $grafanaDBStarURI = "http://$monitorLBIP/api/user/stars/dashboard" - } + # Set Grafana Dashboard endpoint + $grafanaDBURI = $AgConfig.Monitoring["ProdURL"] + "/api/dashboards/db" + $grafanaDBStarURI = $AgConfig.Monitoring["ProdURL"] + "/api/user/stars/dashboard" # Make HTTP request to the API $dashboardID = (Invoke-RestMethod -Method Post -Uri $grafanaDBURI -Headers $adminHeaders -Body $grafanaDBBody).id @@ -1066,7 +1138,307 @@ function Deploy-Prometheus { Invoke-RestMethod -Method Post -Uri "$grafanaDBStarURI/$dashboardID" -Headers $userHeaders | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Observability.log") } - } Write-Host } + +function Update-AzureIoTOpsExtension { + try { + Write-Host "Starting patching of azure-iot-ops extension..." -ForegroundColor Green + & "C:\Program Files\Microsoft SDKs\Azure\CLI2\python.exe" -m pip install -U --target "C:\Program Files\Microsoft SDKs\Azure\CLI2\Lib\site-packages\azure-cli-extensions\azure-iot-ops" azure-identity==1.17.1 + if ($LASTEXITCODE -eq 0) { + Write-Host "Installation of azure-iot-ops extension completed successfully." -ForegroundColor Green + } else { + Write-Host "Installation of azure-iot-ops extension failed with exit code $LASTEXITCODE." -ForegroundColor Red + } + } catch { + Write-Host "An error occurred during the patching of the azure-iot-ops extension." -ForegroundColor Red + Write-Host $_.Exception.Message -ForegroundColor Red + } +} + +# Deploys Azure IoT Operations on all k8s clusters in the config file +function Deploy-AIO { + $sites = $AgConfig.SiteConfig.GetEnumerator() + foreach ($site in $sites) { + if ($site.Value.Type -eq "AKSEE") { + ############################################################## + # Preparing clusters for aio + ############################################################## + $VMnames = $AgConfig.SiteConfig.GetEnumerator().Name.ToLower() + + Invoke-Command -VMName $VMnames -Credential $Credentials -ScriptBlock { + $ProgressPreference = "SilentlyContinue" + ########################################### + # Preparing environment folders structure + ########################################### + Write-Host "[$(Get-Date -Format t)] INFO: Preparing AKSEE clusters for AIO" -ForegroundColor DarkGray + Write-Host "`n" + try { + $localPathProvisionerYaml = "https://raw.githubusercontent.com/Azure/AKS-Edge/main/samples/storage/local-path-provisioner/local-path-storage.yaml" + & kubectl apply -f $localPathProvisionerYaml + $pvcYaml = @" + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: local-path-pvc + namespace: default + spec: + accessModes: + - ReadWriteOnce + storageClassName: local-path + resources: + requests: + storage: 15Gi +"@ + + $pvcYaml | kubectl apply -f - + + Write-Host "Successfully deployment the local path provisioner" + } + catch { + Write-Host "Error: local path provisioner deployment failed" -ForegroundColor Red + } + + Write-Host "Configuring firewall specific to AIO" + Write-Host "Add firewall rule for AIO MQTT Broker" + New-NetFirewallRule -DisplayName "AIO MQTT Broker" -Direction Inbound -Action Allow | Out-Null + try { + $deploymentInfo = Get-AksEdgeDeploymentInfo + # Get the service ip address start to determine the connect address + $connectAddress = $deploymentInfo.LinuxNodeConfig.ServiceIpRange.split("-")[0] + $portProxyRulExists = netsh interface portproxy show v4tov4 | findstr /C:"1883" | findstr /C:"$connectAddress" + if ( $null -eq $portProxyRulExists ) { + Write-Host "Configure port proxy for AIO" + netsh interface portproxy add v4tov4 listenport=1883 listenaddress=0.0.0.0 connectport=1883 connectaddress=$connectAddress | Out-Null + netsh interface portproxy add v4tov4 listenport=1883 listenaddress=0.0.0.0 connectport=18883 connectaddress=$connectAddress | Out-Null + netsh interface portproxy add v4tov4 listenport=1883 listenaddress=0.0.0.0 connectport=8883 connectaddress=$connectAddress | Out-Null + } + else { + Write-Host "Port proxy rule for AIO exists, skip configuring port proxy..." + } + } + catch { + Write-Host "Error: port proxy update for aio failed" -ForegroundColor Red + } + Write-Host "Update the iptables rules" + try { + $iptableRulesExist = Invoke-AksEdgeNodeCommand -NodeType "Linux" -command "sudo iptables-save | grep -- '-m tcp --dport 9110 -j ACCEPT'" -ignoreError + if ( $null -eq $iptableRulesExist ) { + Invoke-AksEdgeNodeCommand -NodeType "Linux" -command "sudo iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 9110 -j ACCEPT" + Write-Host "Updated runtime iptable rules for node exporter" + Invoke-AksEdgeNodeCommand -NodeType "Linux" -command "sudo sed -i '/-A OUTPUT -j ACCEPT/i-A INPUT -p tcp -m tcp --dport 9110 -j ACCEPT' /etc/systemd/scripts/ip4save" + Write-Host "Persisted iptable rules for node exporter" + # increase the maximum number of files + Invoke-AksEdgeNodeCommand -NodeType "Linux" -Command "echo 'fs.inotify.max_user_instances = 1024' | sudo tee -a /etc/sysctl.conf && sudo sysctl -p" + } + else { + Write-Host "iptable rule exists, skip configuring iptable rules..." + } + } + catch { + Write-Host "Error: iptable rule update failed" -ForegroundColor Red + } + } | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\L1Infra.log") + } + } + + ############################################################# + # Deploying AIO on the clusters + ############################################################# + + Write-Host "[$(Get-Date -Format t)] INFO: Deploying AIO to the clusters" -ForegroundColor DarkGray + Write-Host "`n" + $kvIndex = 0 + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + Write-Host "[$(Get-Date -Format t)] INFO: Deploying AIO to the $clusterName cluster" -ForegroundColor Gray + Write-Host "`n" + kubectx $clusterName + $arcClusterName = $AgConfig.SiteConfig[$clusterName].ArcClusterName + "-$namingGuid" + $keyVaultId = (az keyvault list -g $resourceGroup --resource-type vault --query "[$kvIndex].id" -o tsv) + $retryCount = 0 + $maxRetries = 5 + $aioStatus = "notDeployed" + + # Enable custom locations on the Arc-enabled cluster + Write-Host "[$(Get-Date -Format t)] INFO: Enabling custom locations on the Arc-enabled cluster" -ForegroundColor DarkGray + Write-Host "`n" + az config set extension.use_dynamic_install=yes_without_prompt + az connectedk8s enable-features --name $arcClusterName ` + --resource-group $resourceGroup ` + --features cluster-connect custom-locations ` + --custom-locations-oid $customLocationRPOID ` + --only-show-errors + + Start-Sleep -Seconds 10 + + do { + az iot ops init --cluster $arcClusterName.toLower() -g $resourceGroup --kv-id $keyVaultId --sp-app-id $spnClientId --sp-secret $spnClientSecret --sp-object-id $spnObjectId --mq-service-type loadBalancer --mq-insecure true --simulate-plc false --no-block --only-show-errors + if ($? -eq $false) { + $aioStatus = "notDeployed" + Write-Host "`n" + Write-Host "[$(Get-Date -Format t)] Error: An error occured while deploying AIO on the cluster...Retrying" -ForegroundColor DarkRed + Write-Host "`n" + az iot ops init --cluster $arcClusterName.toLower() -g $resourceGroup --kv-id $keyVaultId --sp-app-id $spnClientId --sp-secret $spnClientSecret --sp-object-id $spnObjectId --mq-service-type loadBalancer --mq-insecure true --simulate-plc false --no-block --only-show-errors + $retryCount++ + } + else { + $aioStatus = "deployed" + } + } until ($aioStatus -eq "deployed" -or $retryCount -eq $maxRetries) + $kvIndex++ + } + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + $arcClusterName = $AgConfig.SiteConfig[$clusterName].ArcClusterName + "-$namingGuid" + $retryCount = 0 + $maxRetries = 25 + kubectx $clusterName + do { + $output = az iot ops check --as-object --only-show-errors + $output = $output | ConvertFrom-Json + $mqServiceStatus = ($output.postDeployment | Where-Object { $_.name -eq "evalBrokerListeners" }).status + if ($mqServiceStatus -ne "Success") { + if($retryCount -eq 20 -and $mqServiceStatus -eq "warning"){ + break; + } + Write-Host "Waiting for AIO to be deployed successfully on $clusterName...waiting for 60 seconds" -ForegroundColor DarkGray + Start-Sleep -Seconds 60 + $retryCount++ + } + } until ($mqServiceStatus -eq "Success" -or $retryCount -eq $maxRetries) + + if ($retryCount -eq $maxRetries) { + Write-Host "[$(Get-Date -Format t)] ERROR: AIO deployment failed. Exiting..." -ForegroundColor White -BackgroundColor Red + exit 1 # Exit the script + } + + do{ + $extensionPrincipalId = (az k8s-extension list --cluster-name $arcClusterName --resource-group $resourceGroup --cluster-type "connectedClusters" --query "[?extensionType=='microsoft.iotoperations.mq']" --output json | ConvertFrom-Json).identity.principalId + if($null -eq $extensionPrincipalId){ + Write-Host "Waiting for the mq extension to be installed...waiting for 60 seconds" -ForegroundColor DarkGray + Start-Sleep -Seconds 60 + } + }until($null -ne $extensionPrincipalId) + + Write-Host "AIO deployed successfully on the $clusterName cluster" -ForegroundColor Green + Write-Host "`n" + Write-Host "[$(Get-Date -Format t)] INFO: Started Event Grid role assignment process" -ForegroundColor DarkGray + #$extensionPrincipalId = (az k8s-extension list --cluster-name $arcClusterName --resource-group $resourceGroup --cluster-type "connectedClusters" --query "[?extensionType=='microsoft.iotoperations']" --output json | ConvertFrom-Json).identity.principalId + #$extensionPrincipalId = (az k8s-extension list --cluster-name $arcClusterName --resource-group $resourceGroup --cluster-type "connectedClusters" --query "[?extensionType=='microsoft.iotoperations.mq']" --output json | ConvertFrom-Json).identity.principalId + $eventGridTopicId = (az eventgrid topic list --resource-group $resourceGroup --query "[0].id" -o tsv --only-show-errors) + $eventGridNamespaceName = (az eventgrid namespace list --resource-group $resourceGroup --query "[0].name" -o tsv --only-show-errors) + $eventGridNamespaceId = (az eventgrid namespace list --resource-group $resourceGroup --query "[0].id" -o tsv --only-show-errors) + $eventGridNamespacePrincipalId = (az eventgrid namespace list --resource-group $resourceGroup -o json --only-show-errors | ConvertFrom-Json)[0].identity.principalId + + az role assignment create --assignee-object-id $extensionPrincipalId --role "EventGrid Data Sender" --scope $eventGridTopicId --assignee-principal-type ServicePrincipal --only-show-errors + az role assignment create --assignee-object-id $eventGridNamespacePrincipalId --role "EventGrid Data Sender" --scope $eventGridTopicId --assignee-principal-type ServicePrincipal --only-show-errors + az role assignment create --assignee-object-id $extensionPrincipalId --role "EventGrid TopicSpaces Subscriber" --scope $eventGridNamespaceId --assignee-principal-type ServicePrincipal --only-show-errors + az role assignment create --assignee-object-id $extensionPrincipalId --role 'EventGrid TopicSpaces Publisher' --scope $eventGridNamespaceId --assignee-principal-type ServicePrincipal --only-show-errors + az role assignment create --assignee-object-id $extensionPrincipalId --role "EventGrid TopicSpaces Subscriber" --scope $eventGridTopicId --assignee-principal-type ServicePrincipal --only-show-errors + az role assignment create --assignee-object-id $extensionPrincipalId --role 'EventGrid TopicSpaces Publisher' --scope $eventGridTopicId --assignee-principal-type ServicePrincipal --only-show-errors + + Start-Sleep -Seconds 60 + + Write-Host "[$(Get-Date -Format t)] INFO: Configuring routing to use system-managed identity" -ForegroundColor DarkGray + $eventGridConfig = "{routing-identity-info:{type:'SystemAssigned'}}" + az eventgrid namespace update -g $resourceGroup -n $eventGridNamespaceName --topic-spaces-configuration $eventGridConfig --only-show-errors + + Start-Sleep -Seconds 60 + + ## Adding MQTT bridge to Event Grid MQTT + $mqconfigfile = "$AgToolsDir\mq_cloudConnector.yml" + Copy-Item $mqconfigfile "$AgToolsDir\mq_cloudConnector_$clusterName.yml" -Force + $bridgeConfig = "$AgToolsDir\mq_cloudConnector_$clusterName.yml" + (Get-Content $bridgeConfig) -replace 'clusterName', $clusterName | Set-Content $bridgeConfig + Write-Host "[$(Get-Date -Format t)] INFO: Configuring the MQ Event Grid bridge" -ForegroundColor DarkGray + $eventGridHostName = (az eventgrid namespace list --resource-group $resourceGroup --query "[0].topicSpacesConfiguration.hostname" -o tsv --only-show-errors) + (Get-Content -Path $bridgeConfig) -replace 'eventGridPlaceholder', $eventGridHostName | Set-Content -Path $bridgeConfig + kubectl apply -f $bridgeConfig -n $aioNamespace + + ## Patching MQTT listener + } +} + +function Set-MQTTIpAddress { + $mqttIpArray = @() + $clusters = $AgConfig.SiteConfig.GetEnumerator() + foreach ($cluster in $clusters) { + $clusterName = $cluster.Name.ToLower() + kubectx $clusterName | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\ClusterSecrets.log") + Write-Host "[$(Get-Date -Format t)] INFO: Getting MQ IP address" -ForegroundColor DarkGray + + do { + $mqttIp = kubectl get service $mqListenerService -n $aioNamespace -o jsonpath="{.status.loadBalancer.ingress[0].ip}" + $services = kubectl get pods -n $aioNamespace -o json | ConvertFrom-Json + if($scenario -ne 'contoso_hypermarket'){ + $matchingServices = $services.items | Where-Object { + $_.metadata.name -match "aio-mq-dmqtt" -and + $_.status.phase -notmatch "running" + } + } + else{ + $matchingServices = $services.items | Where-Object { + $_.metadata.name -match "aio-operator" -and + $_.status.phase -notmatch "Running" + } + } + Write-Host "[$(Get-Date -Format t)] INFO: Waiting for MQTT services to initialize and the service Ip address to be assigned...Waiting for 20 seconds" -ForegroundColor DarkGray + Start-Sleep -Seconds 20 + } while ( + $null -eq $mqttIp -and $matchingServices.Count -ne 0 + ) + if (-not [string]::IsNullOrEmpty($mqttIp)) { + $newObject = [PSCustomObject]@{ + cluster = $clusterName + ip = $mqttIp + } + $mqttIpArray += $newObject + } + if($cluster.Value.type -eq "AKSEE"){ + Invoke-Command -VMName $clusterName -Credential $Credentials -ScriptBlock { + netsh interface portproxy add v4tov4 listenport=1883 listenaddress=0.0.0.0 connectport=1883 connectaddress=$using:mqttIp + } + } + } + + $mqttIpArray = $mqttIpArray | Where-Object { $_ -ne "" } + + return $mqttIpArray +} + +############################################################## +# Install MQTT Explorer +############################################################## +function Deploy-MQTTExplorer { + param ( + [array]$mqttIpArray + ) + Write-Host "`n" + Write-Host "[$(Get-Date -Format t)] INFO: Installing MQTT Explorer." -ForegroundColor DarkGreen + Write-Host "`n" + $aioToolsDir = $AgConfig.AgDirectories["AgToolsDir"] + $mqttExplorerSettings = "$env:USERPROFILE\AppData\Roaming\MQTT-Explorer\settings.json" + $latestReleaseTag = (Invoke-WebRequest $mqttExplorerReleasesUrl | ConvertFrom-Json)[0].tag_name + $versionToDownload = $latestReleaseTag.Split("v")[1] + $mqttExplorerReleaseDownloadUrl = ((Invoke-WebRequest $mqttExplorerReleasesUrl | ConvertFrom-Json)[0].assets | Where-object { $_.name -like "MQTT-Explorer-Setup-${versionToDownload}.exe" }).browser_download_url + $output = Join-Path $aioToolsDir "mqtt-explorer-$latestReleaseTag.exe" + $clusters = $AgConfig.SiteConfig.GetEnumerator() + + $ProgressPreference = "SilentlyContinue" + Invoke-WebRequest $mqttExplorerReleaseDownloadUrl -OutFile $output + Start-Process -FilePath $output -ArgumentList "/S" -Wait + + Write-Host "[$(Get-Date -Format t)] INFO: Configuring MQTT explorer" -ForegroundColor DarkGray + Start-Process "$env:USERPROFILE\AppData\Local\Programs\MQTT-Explorer\MQTT Explorer.exe" + Start-Sleep -Seconds 5 + Stop-Process -Name "MQTT Explorer" + Copy-Item "$aioToolsDir\mqtt_explorer_settings.json" -Destination $mqttExplorerSettings -Force + foreach ($cluster in $clusters) { + $clusterName = $cluster.Name.ToLower() + $mqttIp = $mqttIpArray | Where-Object { $_.cluster -eq $clusterName } | Select-Object -ExpandProperty ip + (Get-Content $mqttExplorerSettings ) -replace "${clusterName}IpPlaceholder", $mqttIp | Set-Content $mqttExplorerSettings + } + $ProgressPreference = "Continue" +} \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/PowerShell/Modules/contoso_hypermarket.psm1 b/azure_jumpstart_ag/artifacts/PowerShell/Modules/contoso_hypermarket.psm1 new file mode 100644 index 0000000000..316bb7a478 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/PowerShell/Modules/contoso_hypermarket.psm1 @@ -0,0 +1,1057 @@ +function Get-K3sConfigFile { + # Downloading k3s Kubernetes cluster kubeconfig file + Write-Host "Downloading k3s Kubeconfigs" + $Env:AZCOPY_AUTO_LOGIN_TYPE = "PSCRED" + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + $arcClusterName = $AgConfig.SiteConfig[$clusterName].ArcClusterName + "-$namingGuid" + $containerName = $arcClusterName.toLower() + $sourceFile = "https://$stagingStorageAccountName.blob.core.windows.net/$containerName/config" + azcopy copy $sourceFile "C:\Users\$adminUsername\.kube\ag-k3s-$clusterName" --check-length=false + $sourceFile = "https://$stagingStorageAccountName.blob.core.windows.net/$containerName/*" + azcopy cp --check-md5 FailIfDifferentOrMissing $sourceFile "$AgLogsDir\" --include-pattern "*.log" + } +} + +function Merge-K3sConfigFiles { + + $mergedKubeconfigPath = "C:\Users\$adminUsername\.kube\config" + + $kubeconfig1Path = "C:\Users\$adminUsername\.kube\ag-k3s-seattle" + $kubeconfig2Path = "C:\Users\$adminUsername\.kube\ag-k3s-chicago" + + # Extract base file names (without extensions) to use as new names + $suffix1 = [System.IO.Path]::GetFileNameWithoutExtension($kubeconfig1Path) + $suffix2 = [System.IO.Path]::GetFileNameWithoutExtension($kubeconfig2Path) + + # Load the kubeconfig files, ensuring no empty lines or structures + $kubeconfig1 = get-content $kubeconfig1Path | ConvertFrom-Yaml + $kubeconfig2 = get-content $kubeconfig2Path | ConvertFrom-Yaml + + # Function to replace cluster, user, and context names with the file name, while keeping original server addresses + function Set-NamesWithFileName { + param ( + [hashtable]$kubeconfigData, + [string]$newName + ) + + # Replace cluster names but keep the server addresses + foreach ($cluster in $kubeconfigData.clusters) { + if ($cluster.name -and $cluster.cluster.server) { + $cluster.name = "$newName" + } + } + + # Replace user names + foreach ($user in $kubeconfigData.users) { + if ($user.name) { + $user.name = "$newName" + } + } + + # Replace context names, but retain the correct mapping to cluster and user + foreach ($context in $kubeconfigData.contexts) { + if ($context.name -and $context.context.cluster -and $context.context.user) { + $context.name = "$newName" + $context.context.cluster = "$newName" + $context.context.user = "$newName" + } + } + + return $kubeconfigData + } + + # Apply renaming using file names + $kubeconfig1 = Set-NamesWithFileName -kubeconfigData $kubeconfig1 -newName $suffix1 + $kubeconfig2 = Set-NamesWithFileName -kubeconfigData $kubeconfig2 -newName $suffix2 + + # Merge the clusters, users, and contexts from both kubeconfigs + $mergedClusters = $kubeconfig1.clusters + $kubeconfig2.clusters + $mergedUsers = $kubeconfig1.users + $kubeconfig2.users + $mergedContexts = $kubeconfig1.contexts + $kubeconfig2.contexts + + # Prepare the merged kubeconfig ensuring no empty or null fields + $mergedKubeconfig = @{ + apiVersion = $kubeconfig1.apiVersion + kind = $kubeconfig1.kind + clusters = $mergedClusters | Where-Object { $_.name -and $_.cluster.server } + users = $mergedUsers | Where-Object { $_.name } + contexts = $mergedContexts | Where-Object { $_.name -and $_.context.cluster -and $_.context.user } + "current-context" = $kubeconfig1."current-context" # Retain the current context of the first file + } + + # Convert the merged data back to YAML and save to a new file + $mergedKubeconfig | ConvertTo-Yaml | Set-Content -Path $mergedKubeconfigPath + + Write-Host "Kubeconfig files successfully merged into $mergedKubeconfigPath" + kubectx seattle="ag-k3s-seattle" + kubectx chicago="ag-k3s-chicago" + +} + +function Set-K3sClusters { + Write-Host "Configuring kube-vip on K3s clusters" + #az login --service-principal --username $Env:spnClientID --password=$Env:spnClientSecret --tenant $Env:spnTenantId + az login --identity + az account set -s $subscriptionId + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + if ($cluster.Value.Type -eq "k3s") { + $clusterName = $cluster.Value.FriendlyName.ToLower() + $vmName = $cluster.Value.ArcClusterName + "-$namingGuid" + kubectx $clusterName + $k3sVIP = $(az network nic ip-config list --resource-group $Env:resourceGroup --nic-name $vmName-NIC --query "[?primary == ``true``].privateIPAddress" -otsv) + Write-Host "Assigning kube-vip-role on k3s cluster" + $kubeVipRbac = "$($Agconfig.AgDirectories.AgToolsDir)\kubeVipRbac.yml" + kubectl apply -f $kubeVipRbac + + $kubeVipDaemonset = "$($Agconfig.AgDirectories.AgToolsDir)\kubeVipDaemon.yml" + (Get-Content -Path $kubeVipDaemonset) -replace 'k3sVIPPlaceholder', "$k3sVIP" | Set-Content -Path $kubeVipDaemonset + kubectl apply -f $kubeVipDaemonset + + Write-Host "Deploying Kube vip cloud controller on k3s cluster" + kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml + + $serviceIpRange = $(az network nic ip-config list --resource-group $Env:resourceGroup --nic-name $vmName-NIC --query "[?primary == ``false``].privateIPAddress" -otsv) + $sortedIps = $serviceIpRange | Sort-Object { [System.Version]$_ } + $lowestServiceIp = $sortedIps[0] + $highestServiceIp = $sortedIps[-1] + + kubectl create configmap -n kube-system kubevip --from-literal range-global=$lowestServiceIp-$highestServiceIp + Start-Sleep -Seconds 30 + + # Write-Host "Creating longhorn storage on K3scluster" + # kubectl apply -f "$($Agconfig.AgDirectories.AgToolsDir)\longhorn.yaml" + # Start-Sleep -Seconds 30 + # Write-Host "`n" + } + } +} + +function Deploy-AIO-M3 { + Write-Host "[$(Get-Date -Format t)] INFO: Deploying AIO to the Arc-enabled clusters" -ForegroundColor Gray + Write-Host "`n" + + # Get Event Hub details from the resource group to assign role permissions to IoT Operations extension managed + $eventHubInfo = (az resource list --resource-group $resourceGroup --resource-type "Microsoft.EventHub/namespaces" | ConvertFrom-Json) + if ($eventHubInfo.Count -ne 1) { + Write-Host "ERROR: Resource group contains no Eventhub namespaces or more than one. Make sure to have only one EventHub namesapce in the resource group." -ForegroundColor DarkRed + return + } + + $eventHubNamespace =$eventHubInfo[0].name + $eventHubNamespaceId = $eventHubInfo[0].id + $evenHubNamespaceHost = "$($eventHubNamespace).servicebus.windows.net:9093" + + Write-Host "INFO: Found EventHub Namespace with Resource ID: $eventHubNamespaceId" -ForegroundColor DarkGray + + # Get Event Hub from the Event Hub namespace + $eventHubs = az eventhubs eventhub list --namespace-name $eventHubInfo[0].name --resource-group $resourceGroup | ConvertFrom-Json + $eventHubName = $eventHubs[0].name + if (-not $eventHubName) { + Write-Host "[$(Get-Date -Format t)] ERROR: Event Hub not found in the EventHub namespace $($eventHubInfo[0].name)" -ForegroundColor DarkRed + return + } + + # Download the bicep template + $dataflowBicepTemplatePath = "$($AgConfig.AgDirectories.AgTempDir)\dataflows.bicep" + Invoke-WebRequest ($templateBaseUrl + "contoso_hypermarket/bicep/data/dataflows.bicep") -OutFile $dataflowBicepTemplatePath + if (-not (Test-Path -Path $dataflowBicepTemplatePath)) { + Write-Host "[$(Get-Date -Format t)] ERROR: $dataflowBicepTemplatePath file not found." -ForegroundColor DarkRed + return + } + + $kvIndex = 0 + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + Write-Host "[$(Get-Date -Format t)] INFO: Deploying AIO to the $clusterName cluster" -ForegroundColor Gray + Write-Host "`n" + # Create user-assigned identity for AIO secrets management + Write-Host "Create user-assigned identity for AIO secrets management" -ForegroundColor DarkGray + Write-Host "`n" + $userAssignedManagedIdentityKvName = "aio-${clusterName}-${namingGuid}-kv-identity" + $userAssignedMIKvResourceId = $(az identity create -g $resourceGroup -n $userAssignedManagedIdentityKvName -o tsv --query id) + + # Create user-assigned identity for AIO secrets management + Write-Host "Create user-assigned identity for cloud connections" -ForegroundColor DarkGray + Write-Host "`n" + $userAssignedManagedIdentityCloudName = "aio-${clusterName}-${namingGuid}-cloud-identity" + $userAssignedMICloudResourceId = $(az identity create -g $resourceGroup -n $userAssignedManagedIdentityCloudName -o tsv --query id) + + kubectx $clusterName + $arcClusterName = $AgConfig.SiteConfig[$clusterName].ArcClusterName + "-$namingGuid" + $keyVaultId = (az keyvault list -g $resourceGroup --resource-type vault --query "[$kvIndex].id" -o tsv) + $retryCount = 0 + $maxRetries = 5 + $aioStatus = "notDeployed" + + # Enable custom locations on the Arc-enabled cluster + Write-Host "[$(Get-Date -Format t)] INFO: Enabling custom locations on the Arc-enabled cluster" -ForegroundColor DarkGray + Write-Host "`n" + az config set extension.use_dynamic_install=yes_without_prompt + az connectedk8s enable-features --name $arcClusterName ` + --resource-group $resourceGroup ` + --features cluster-connect custom-locations ` + --custom-locations-oid $customLocationRPOID ` + --only-show-errors + + # Create the Schema registry for the cluster + Write-Host "[$(Get-Date -Format t)] INFO: Creating the schema registry on the Arc-enabled cluster" -ForegroundColor DarkGray + Write-Host "`n" + $schemaName = "${clusterName}-$($Env:namingGuid)-schema" + $schemaId = $(az iot ops schema registry create --name $schemaName ` + --resource-group $resourceGroup ` + --registry-namespace "$clusterName-$($Env:namingGuid)-namespace" ` + --sa-resource-id $(az storage account show --name $aioStorageAccountName --resource-group $resourceGroup -o tsv --query id) ` + --query id -o tsv) + + $customLocationName = $arcClusterName.toLower() + "-cl" + + # Initialize the Azure IoT Operations instance on the Arc-enabled cluster + Write-Host "[$(Get-Date -Format t)] INFO: Initialize the Azure IoT Operations instance on the Arc-enabled cluster" -ForegroundColor DarkGray + Write-Host "`n" + do { + az iot ops init --cluster $arcClusterName.toLower() ` + --resource-group $resourceGroup ` + --subscription $subscriptionId ` + --only-show-errors + if ($? -eq $false) { + $aioStatus = "notDeployed" + Write-Host "`n" + Write-Host "[$(Get-Date -Format t)] Error: An error occured while deploying AIO on the cluster...Retrying" -ForegroundColor DarkRed + Write-Host "`n" + az iot ops init --cluster $arcClusterName.toLower() ` + --resource-group $resourceGroup ` + --subscription $subscriptionId ` + --only-show-errors + $retryCount++ + } + else { + $aioStatus = "deployed" + } + } until ($aioStatus -eq "deployed" -or $retryCount -eq $maxRetries) + + $retryCount = 0 + $maxRetries = 5 + # Create the Azure IoT Operations instance on the Arc-enabled cluster + Write-Host "[$(Get-Date -Format t)] INFO: Create the Azure IoT Operations instance on the Arc-enabled cluster" -ForegroundColor DarkGray + Write-Host "`n" + do { + az iot ops create --name $arcClusterName.toLower() ` + --cluster $arcClusterName.toLower() ` + --resource-group $resourceGroup ` + --subscription $subscriptionId ` + --custom-location $customLocationName ` + --sr-resource-id $schemaId ` + --enable-rsync true ` + --add-insecure-listener true ` + --only-show-errors + + if ($? -eq $false) { + $aioStatus = "notDeployed" + Write-Host "`n" + Write-Host "[$(Get-Date -Format t)] Error: An error occured while deploying AIO on the cluster...Retrying" -ForegroundColor DarkRed + Write-Host "`n" + az iot ops create --name $arcClusterName.toLower() ` + --cluster $arcClusterName.toLower() ` + --resource-group $resourceGroup ` + --subscription $subscriptionId ` + --custom-location $customLocationName ` + --sr-resource-id $schemaId ` + --enable-rsync true ` + --add-insecure-listener true ` + --only-show-errors + + $retryCount++ + } + else { + $aioStatus = "deployed" + } + } until ($aioStatus -eq "deployed" -or $retryCount -eq $maxRetries) + + # Configure the Azure IoT Operations instance for secret synchronization + Write-Host "[$(Get-Date -Format t)] INFO: Configuring the Azure IoT Operations instance for secret synchronization" -ForegroundColor DarkGray + Write-Host "`n" + + # Enable OIDC issuer and workload identity on the Arc-enabled cluster + az connectedk8s update -n $arcClusterName ` + --resource-group $resourceGroup ` + --enable-oidc-issuer ` + --enable-workload-identity + + Write-Host "[$(Get-Date -Format t)] INFO: Assigning the user-assigned managed identity to the Azure IoT Operations instance" -ForegroundColor DarkGray + Write-Host "`n" + az iot ops identity assign --name $arcClusterName.toLower() ` + --resource-group $resourceGroup ` + --mi-user-assigned $userAssignedMIKvResourceId + + Start-Sleep -Seconds 60 + + Write-Host "[$(Get-Date -Format t)] INFO: Configure the Azure IoT Operations instance for secret synchronization" -ForegroundColor DarkGray + Write-Host "`n" + + az iot ops secretsync enable --instance $arcClusterName.toLower() ` + --kv-resource-id $keyVaultId ` + --resource-group $resourceGroup ` + --mi-user-assigned $userAssignedMICloudResourceId ` + --only-show-errors + + $kvIndex++ + + # Get IoT Operations extension pricipalId + Write-Host "[$(Get-Date -Format t)] INFO: Retrieving IoT Operations extension principalId" -ForegroundColor DarkGray + $iotExtensionPrincipalId = (az k8s-extension list --resource-group $resourceGroup --cluster-name $arcClusterName --cluster-type connectedClusters --query "[?extensionType=='microsoft.iotoperations'].identity.principalId" -o tsv) + Write-Host "[$(Get-Date -Format t)] INFO: IoT Operations extension principalId is $iotExtensionPrincipalId" -ForegroundColor DarkGray + + # Assign "Azure Event Hubs Data Sender" role to IoT managed identity + Write-Host "[$(Get-Date -Format t)] INFO: Assigning 'Azure Event Hubs Data Sender role' to '$iotExtensionPrincipalId' to EventHub namespace" -ForegroundColor DarkGray + az role assignment create --assignee-object-id $iotExtensionPrincipalId --role "Azure Event Hubs Data Sender" --scope $eventHubNamespaceId --assignee-principal-type ServicePrincipal --only-show-errors + + # Deploy IoT DataFlows using bicep template + Write-Host "[$(Get-Date -Format t)] INFO: Deploying IoT DataFlows using bicep template" -ForegroundColor DarkGray + $deploymentName = "$arcClusterName" + "-iot-dataflow" + $iotInstanceName = $arcClusterName.toLower() + + Write-Host "[$(Get-Date -Format t)] INFO: az deployment group create --name $deploymentName --resource-group $resourceGroup --template-file $dataflowBicepTemplatePath --parameters aioInstanceName=$iotInstanceName evenHubNamespaceHost=$evenHubNamespaceHost eventHubName=$eventHubName customLocationName=$customLocationName" + az deployment group create --name $deploymentName --resource-group $resourceGroup --template-file $dataflowBicepTemplatePath ` + --parameters aioInstanceName=$iotInstanceName evenHubNamespaceHost=$evenHubNamespaceHost eventHubName=$eventHubName ` + customLocationName=$customLocationName + + # Verify the deployment status + $deploymentStatus = az deployment group show --name $deploymentName --resource-group $resourceGroup --query properties.provisioningState -o tsv + if ($deploymentStatus -eq "Succeeded") { + Write-Host "[$(Get-Date -Format t)] INFO: Deployment succeeded for $deploymentName" -ForegroundColor Green + } + else { + Write-Host "[$(Get-Date -Format t)] ERROR: Deployment failed for $deploymentName" -ForegroundColor Red + } + } +} + +function Set-MicrosoftFabric { + + # Load Agconfig + $fabricWorkspacePrefix = $AgConfig.FabricConfig["WorkspacePrefix"] + $fabricWorkspaceName = "$fabricWorkspacePrefix-$namingGuid" + $fabricFolder = $AgConfig.AgDirectories["AgFabric"] + $runFabricSetupAs = $AgConfig.FabricConfig["RunFabricSetupAs"] + $fabricConfigFile = "$fabricFolder\fabric-config.json" + $eventHubKeyName = $AgConfig.FabricConfig["EventHubSharedAccessKeyName"] + + Write-Host "[$(Get-Date -Format t)] INFO: Creating Microsoft Fabric workspace configuration file $fabricConfigFile" -ForegroundColor DarkGray + + # Get Fabric capacity name from the resource group + $fabricCapacityName = (az fabric capacity list --resource-group $Env:resourceGroup --query "[0].name" -o tsv) + if (-not $fabricCapacityName) { + Write-Host "[$(Get-Date -Format t)] WARNING: Fabric capacity not found in the resource group $Env:resourceGroup. Make sure either you have Fabric Capacity or other Fabric license to create Farbric worspace." -ForegroundColor Yellow + } + else { + Write-Host "[$(Get-Date -Format t)] INFO: Found fabric capacity '$fabricCapacityName' in the resource group $Env:resourceGroup." -ForegroundColor DarkGray + } + + # Get EventHub namespace created in the resource group + $eventHubNamespace = (az eventhubs namespace list --resource-group $Env:resourceGroup --query "[0].name" -o tsv) + if (-not $eventHubNamespace) { + Write-Error "$(Get-Date -Format t)] INFO: EventHub namespaces not found in the resource group $Env:resourceGroup" -ForegroundColor DarkRed + return + } + + # Get Event Hub from the Event Hub namespace + $eventHubs = az eventhubs eventhub list --namespace-name $eventHubNamespace --resource-group $resourceGroup | ConvertFrom-Json + $eventHubName = $eventHubs[0].name + if (-not $eventHubName) { + Write-Host "[$(Get-Date -Format t)] ERROR: Event Hub not found in the EventHub namespace $eventHubNamespace" -ForegroundColor DarkRed + return + } + + # Get Event Hub credentials + Write-Host "INFO: Retrieving Event Hub key for '$eventHubKeyName' Shared Acess Policy." + $eventHubKeyName = $AgConfig.FabricConfig["EventHubSharedAccessKeyName"] + $eventHubKey = az eventhubs namespace authorization-rule keys list --resource-group $resourceGroup --namespace-name $eventHubNamespace --name $eventHubKeyName --query primaryKey --output tsv + if ($eventHubKey -eq '') { + Write-Host "$(Get-Date -Format t)] ERROR: Failed to retrieve Event Hub key." -ForegroundColor DarkRed + return + } + + Write-Host "$(Get-Date -Format t)] INFO: Received Event Hub key." -ForegroundColor DarkGray + + # Store EventHub key in the environment variable to use in Farbic setup script + [System.Environment]::SetEnvironmentVariable('eventHubPrimaryKey', $eventHubKey, [System.EnvironmentVariableTarget]::Machine) + [System.Environment]::SetEnvironmentVariable('eventHubNamespace', $eventHubNamespace, [System.EnvironmentVariableTarget]::Machine) + [System.Environment]::SetEnvironmentVariable('eventHubName', $eventHubName, [System.EnvironmentVariableTarget]::Machine) + + $configJson = @" + { + "tenantID": "$Env:tenantId", + "subscriptionID": "$Env:subscriptionId", + "runAs": "$runFabricSetupAs", + "azureLocation": "$Env:azureLocation", + "resourceGroup": "$Env:resourceGroup", + "fabricCapacityName": "$fabricCapacityName", + "templateBaseUrl": "$Env:templateBaseUrl", + "fabricWorkspaceName": "$fabricWorkspaceName", + "eventHubNamespace": "$eventHubNamespace", + "eventHubName": "$eventHubName", + "eventHubKeyName": "$eventHubKeyName", + "eventHubPrimaryKey": "$eventHubKey" + } +"@ + + $configJson | Set-Content -Path $fabricConfigFile + Write-Host "$(Get-Date -Format t)] INFO: Fabric config file $fabricConfigFile created" + + # Download Fabric workspace setup script from GitHuB + $fabricSetupScriptFile = "SetupFabricWorkspace.ps1" + $sriptFileUrl = $templateBaseUrl + "artifacts/PowerShell/$fabricSetupScriptFile" + Write-Host "$(Get-Date -Format t)] INFO: Downloading script file from $sriptFileUrl" + + $scriptFilePath = "$fabricFolder\$fabricSetupScriptFile" + Invoke-WebRequest ($sriptFileUrl) -OutFile $scriptFilePath + if (-not (Test-Path -Path $scriptFilePath)) { + Write-Host "[$(Get-Date -Format t)] ERROR: Unable to download script file from $sriptFileUrl" -ForegroundColor DarkRed + } + Write-Host "$(Get-Date -Format t)] INFO: Downloaded script file $scriptFilePath" +} + +function Deploy-HypermarketConfigs { + # Loop through the clusters and deploy the configs in AppConfig hashtable in AgConfig-contoso-hypermarket.psd + Write-Host "INFO: Cloning the GitHub repository locally to get helm chart" -ForegroundColor Gray + git clone "https://github.com/Azure/jumpstart-apps.git" + + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + kubectx $clusterName + helm dependency build ".\jumpstart-apps\agora\contoso_hypermarket\charts\contoso-hypermarket" --namespace contoso-hypermarket + helm install contoso-hypermarket ".\jumpstart-apps\agora\contoso_hypermarket\charts\contoso-hypermarket" --create-namespace --namespace contoso-hypermarket + } +} + +# function Deploy-HypermarketConfigs { + +# # Loop through the clusters and deploy the configs in AppConfig hashtable in AgConfig-contoso-hypermarket.psd +# foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { +# Start-Job -Name gitops -ScriptBlock { +# $AgConfig = $using:AgConfig +# $cluster = $using:cluster +# $namingGuid = $using:namingGuid +# $resourceGroup = $using:resourceGroup +# $appClonedRepo = $using:appUpstreamRepo +# $appsRepo = $using:appsRepo + +# $AgConfig.AppConfig.GetEnumerator() | sort-object -Property @{Expression = { $_.value.Order }; Ascending = $true } | ForEach-Object { +# $app = $_ +# $clusterName = $cluster.value.ArcClusterName + "-$namingGuid" +# $branch = $cluster.value.Branch.ToLower() +# $configName = $app.value.GitOpsConfigName.ToLower() +# $namespace = $app.value.Namespace +# $appName = $app.Value.KustomizationName +# $appPath = $app.Value.KustomizationPath +# $retryCount = 0 +# $maxRetries = 2 + +# Write-Host "[$(Get-Date -Format t)] INFO: Creating GitOps config for $configName on $($cluster.Value.ArcClusterName+"-$namingGuid")" -ForegroundColor Gray +# $type = "connectedClusters" + +# az k8s-configuration flux create ` +# --cluster-name $clusterName ` +# --resource-group $resourceGroup ` +# --name $configName ` +# --cluster-type $type ` +# --scope cluster ` +# --url $appClonedRepo ` +# --branch $branch ` +# --sync-interval 3s ` +# --kustomization name=$appName path=$appPath prune=true retry_interval=1m ` +# --timeout 10m ` +# --namespace $namespace ` +# --only-show-errors ` +# 2>&1 | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + +# do { +# $configStatus = $(az k8s-configuration flux show --name $configName --cluster-name $clusterName --cluster-type $type --resource-group $resourceGroup -o json 2>$null) | convertFrom-JSON +# if ($configStatus.ComplianceState -eq "Compliant") { +# Write-Host "[$(Get-Date -Format t)] INFO: GitOps configuration $configName is ready on $clusterName" -ForegroundColor DarkGreen | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") +# } +# else { +# if ($configStatus.ComplianceState -ne "Non-compliant") { +# Start-Sleep -Seconds 20 +# } +# elseif ($configStatus.ComplianceState -eq "Non-compliant" -and $retryCount -lt $maxRetries) { +# Start-Sleep -Seconds 20 +# $configStatus = $(az k8s-configuration flux show --name $configName --cluster-name $clusterName --cluster-type $type --resource-group $resourceGroup -o json 2>$null) | convertFrom-JSON +# if ($configStatus.ComplianceState -eq "Non-compliant" -and $retryCount -lt $maxRetries) { +# $retryCount++ +# Write-Host "[$(Get-Date -Format t)] INFO: Attempting to re-install $configName on $clusterName" -ForegroundColor Gray | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") +# Write-Host "[$(Get-Date -Format t)] INFO: Deleting $configName on $clusterName" -ForegroundColor Gray | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") +# az k8s-configuration flux delete ` +# --resource-group $resourceGroup ` +# --cluster-name $clusterName ` +# --cluster-type $type ` +# --name $configName ` +# --force ` +# --yes ` +# --only-show-errors ` +# 2>&1 | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + +# Start-Sleep -Seconds 10 +# Write-Host "[$(Get-Date -Format t)] INFO: Re-creating $configName on $clusterName" -ForegroundColor Gray | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + +# az k8s-configuration flux create ` +# --cluster-name $clusterName ` +# --resource-group $resourceGroup ` +# --name $configName ` +# --cluster-type $type ` +# --scope cluster ` +# --url $appClonedRepo ` +# --branch $branch ` +# --sync-interval 3s ` +# --kustomization name=$appName path=$appPath prune=true ` +# --timeout 30m ` +# --namespace $namespace ` +# --only-show-errors ` +# 2>&1 | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") +# } +# } +# elseif ($configStatus.ComplianceState -eq "Non-compliant" -and $retryCount -eq $maxRetries) { +# Write-Host "[$(Get-Date -Format t)] ERROR: GitOps configuration $configName has failed on $clusterName. Exiting..." -ForegroundColor White -BackgroundColor Red | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") +# break +# } +# } +# } until ($configStatus.ComplianceState -eq "Compliant") +# } +# } +# } +# while ($(Get-Job -Name gitops).State -eq 'Running') { +# Write-Host "[$(Get-Date -Format t)] INFO: Waiting for GitOps configuration to complete on all clusters...waiting 60 seconds" -ForegroundColor Gray +# Receive-Job -Name gitops -WarningAction SilentlyContinue +# Start-Sleep -Seconds 60 +# } + +# Get-Job -name gitops | Remove-Job +# Write-Host "[$(Get-Date -Format t)] INFO: GitOps configuration complete." -ForegroundColor Green +# Write-Host +# } + +function Set-AIServiceSecrets { + $location = $global:azureLocation + $azureOpenAIModelName = ($Env:azureOpenAIModel | ConvertFrom-Json).name + $azureOpenAIApiVersion = ($Env:azureOpenAIModel | ConvertFrom-Json).apiVersion + $AIServiceAccountName = $(az cognitiveservices account list -g $resourceGroup --query [].name -o tsv) + $AIServicesEndpoints = $(az cognitiveservices account show --name $AIServiceAccountName --resource-group $resourceGroup --query properties.endpoints) | ConvertFrom-Json -AsHashtable + $speechToTextEndpoint = $AIServicesEndpoints['Speech Services Speech to Text (Standard)'] + $openAIEndpoint = $AIServicesEndpoints['OpenAI Language Model Instance API'] + $AIServicesKey = $(az cognitiveservices account keys list --name $AIServiceAccountName --resource-group $resourceGroup --query key1 -o tsv) + + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + Write-Host "[$(Get-Date -Format t)] INFO: Deploying AI services Secret to the $clusterName cluster" -ForegroundColor Gray + Write-Host "`n" + kubectx $clusterName + kubectl create secret generic azure-openai-secret ` + --namespace=contoso-hypermarket ` + --from-literal=azure-openai-endpoint=$openAIEndpoint ` + --from-literal=azure-openai-key=$AIServicesKey ` + --from-literal=azure-speech-to-text-endpoint=$speechToTextEndpoint ` + --from-literal=region=$location ` + --from-literal=azure-openai-model-name=$azureOpenAIModelName ` + --from-literal=azure-openai-deployment-name=$openAIDeploymentName ` + --from-literal=azure-openai-api-version=$azureOpenAIApiVersion + } +} + +function Set-EventHubSecrets { + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + Write-Host "[$(Get-Date -Format t)] INFO: Deploying EventHub Secret to the $clusterName cluster" -ForegroundColor Gray + Write-Host "`n" + $eventHubNamespace = $(az eventhubs namespace list -g $resourceGroup --query [].name -o tsv) + $eventHubName = $(az eventhubs eventhub list -g $resourceGroup --namespace-name $eventHubNamespace --query [].name -o tsv) + $eventHubConnectionString = $(az eventhubs eventhub authorization-rule keys list --resource-group $resourceGroup --namespace-name $eventHubNamespace --eventhub-name $eventHubName --name RootManageSharedAccessKey --query primaryConnectionString -o tsv) + kubectx $clusterName + kubectl create secret generic azure-eventhub-secret ` + --namespace=contoso-hypermarket ` + --from-literal=azure-eventhub-connection-string=$eventHubConnectionString + } +} + +function Set-SQLSecret { + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + Write-Host "[$(Get-Date -Format t)] INFO: Deploying SQL Secret to the $clusterName cluster" -ForegroundColor Gray + Write-Host "`n" + $decodeAdminPassword = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($adminPassword)) + kubectx $clusterName + kubectl create secret generic azure-sqlpassword-secret ` + --namespace=contoso-hypermarket ` + --from-literal=azure-sqlpassword-secret=$decodeAdminPassword + } +} + +function Set-LoadBalancerBackendPools { + $vnetResourceId = $(az network vnet list -g $resourceGroup --query [].id -o tsv) + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + $loadBalancerName = "Ag-LoadBalancer-${clusterName}" + $loadBalancerPublicIp = "Ag-LB-Frontend-${clusterName}" + kubectx $clusterName | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + $services = kubectl get services -n contoso-hypermarket -o json | ConvertFrom-Json + $services.items | ForEach-Object { + $service = $_ + $serviceName = $service.metadata.name + $servicePorts = $service.spec.ports.port + $serviceIp = $service.status.loadBalancer.ingress.ip + + if($serviceName -eq "influxdb"){ + $servicePort = $servicePorts[1] + }else{ + $servicePort = $servicePorts[0] + } + + if ($null -ne $serviceIp) { + Write-Host "[$(Get-Date -Format t)] Creating backend pool for service: $serviceName" -ForegroundColor Gray + Write-Host "`n" + + az network lb address-pool create -g $resourceGroup ` + --lb-name $loadBalancerName ` + --name "$serviceName-pool" ` + --vnet $vnetResourceId ` + --backend-addresses "[{name:${serviceName},ip-address:${serviceIp}}]" ` + --only-show-errors | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\loadBalancer.log") + + Write-Host "[$(Get-Date -Format t)] Creating inbound NAT rule for service: $serviceName" -ForegroundColor Gray + Write-Host "`n" + az network lb inbound-nat-rule create -g $resourceGroup ` + --lb-name $loadBalancerName ` + --name "$serviceName-NATRule" ` + --protocol Tcp ` + --frontend-port-range-start $servicePort ` + --frontend-port-range-end $servicePort ` + --frontend-ip $loadBalancerPublicIp ` + --backend-address-pool "$serviceName-pool" ` + --backend-port $servicePort ` + --only-show-errors | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\loadBalancer.log") + } + } + + # Grafana backend pool creation + $clientVMName = "Ag-VM-Client" + $serviceName = "Grafana" + $servicePort = "3000" + $clientVMIpAddress = $(az vm list-ip-addresses --name $clientVMName ` + --resource-group $resourceGroup ` + --query "[].virtualMachine.network.privateIpAddresses[0]" ` + --output tsv ` + --only-show-errors) + + Write-Host "[$(Get-Date -Format t)] Creating inbound NAT rule for service: $serviceName" -ForegroundColor Gray + Write-Host "`n" + + az network lb address-pool create -g $resourceGroup ` + --lb-name $loadBalancerName ` + --name "$serviceName-pool" ` + --vnet $vnetResourceId ` + --backend-addresses "[{name:Grafana,ip-address:${clientVMIpAddress}}]" ` + --only-show-errors | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\loadBalancer.log") + + Write-Host "[$(Get-Date -Format t)] Creating inbound NAT rule for service: $serviceName" -ForegroundColor Gray + Write-Host "`n" + + az network lb inbound-nat-rule create -g $resourceGroup ` + --lb-name $loadBalancerName ` + --name "$serviceName-NATRule" ` + --protocol Tcp ` + --frontend-port-range-start $servicePort ` + --frontend-port-range-end $servicePort ` + --frontend-ip $loadBalancerPublicIp ` + --backend-address-pool "$serviceName-pool" ` + --backend-port $servicePort ` + --only-show-errors | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\loadBalancer.log") + + Write-Host "[$(Get-Date -Format t)] Creating outbound rule for service: $serviceName" -ForegroundColor Gray + Write-Host "`n" + + az network lb outbound-rule create --address-pool "$serviceName-pool"` + --lb-name $loadBalancerName ` + --name "Grafana-outbound" ` + --outbound-ports 10000 ` + --protocol All ` + --frontend-ip-configs $loadBalancerPublicIp ` + --resource-group $resourceGroup ` + --only-show-errors | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\loadBalancer.log") + } + +} + +function Set-ACSA { + # Begin ACSA Installation. + # Documentation: https://aepreviews.ms/docs/edge-storage-accelerator/how-to-install-edge-storage-accelerator/ + + # Ensure necessary variables are available + $storageAccountName = $global:aioStorageAccountName # Using $global:aioStorageAccountName + $storageContainer = "shopper-videos" # Container name set to "shoppervideos" + $resourceGroup = $global:resourceGroup + $arcClusterName = $global:k3sArcClusterName + $subscriptionId = $global:subscriptionId + + # Create a storage account + Write-Host "Storage Account Name: $storageAccountName" + Write-Host "Container Name: $storageContainer" + + # Create a container within the storage account + Write-Host "Creating container within the storage account..." + az storage container create ` + --name "$storageContainer" ` + --account-name "$storageAccountName" ` + --auth-mode login + + # Assign necessary role to the extension principal + $principalID = $(az k8s-extension list ` + --cluster-name $arcClusterName ` + --resource-group $resourceGroup ` + --cluster-type connectedClusters ` + --query "[?extensionType=='microsoft.arc.containerstorage'].identity.principalId | [0]" -o tsv) + + az role assignment create ` + --assignee-object-id $principalID ` + --assignee-principal-type ServicePrincipal ` + --role "Storage Blob Data Owner" ` + --scope "/subscriptions/$subscriptionId/resourceGroups/$resourceGroup/providers/Microsoft.Storage/storageAccounts/$storageAccountName" + + # Deploy the ACSA application #NEED TO BE CHANGED + $acsadeployYamlUrl = "https://raw.githubusercontent.com/microsoft/azure_arc/main/azure_edge_iot_ops_jumpstart/acsa_fault_detection/yaml/acsa-edge-sub-volume.yaml" + $acsadeployYamlPath = "acsa-edge-sub-volume.yaml" + Invoke-WebRequest -Uri $acsadeployYamlUrl -OutFile $acsadeployYamlPath + + # Replace {STORAGEACCOUNT} with the actual storage account name + (Get-Content $acsadeployYamlPath) -replace '{STORAGEACCOUNT}', $storageAccountName | Set-Content $acsadeployYamlPath + + # Apply the acsa-deploy.yaml file using kubectl + Write-Host "Applying acsa-deploy.yaml configuration..." + kubectl apply -f $acsadeployYamlPath + Write-Host "acsa-deploy.yaml configuration applied successfully." +} + +function Deploy-HypermarketBookmarks { + $bookmarksFileName = "$AgToolsDir\Bookmarks" + $edgeBookmarksPath = "$Env:LOCALAPPDATA\Microsoft\Edge\User Data\Default" + + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + kubectx $clusterName | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + $publicIPAddress = $(az network public-ip show --resource-group $resourceGroup --name "Ag-LB-Public-IP-$clusterName" --query "ipAddress" --output tsv) + $services = kubectl get services -n contoso-hypermarket -o json | ConvertFrom-Json + + # Matching url: backend-api + $matchingServices = $services.items | Where-Object { + $_.metadata.name -eq 'backend-api' -and + $_.spec.ports.port -contains 5002 + } + $backendApiIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($backendApiIp in $backendApiIps) { + $output = "http://${publicIPAddress}:5002/docs" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("backend-api-" + $clusterName + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + Start-Sleep -Seconds 2 + } + + # Matching url: cerebral-api-service + $matchingServices = $services.items | Where-Object { + $_.metadata.name -eq 'cerebral-api-service' -and + $_.spec.ports.port -contains 5003 + } + $backendApiIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($backendApiIp in $backendApiIps) { + $output = "http://${publicIPAddress}:5003" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("cerebral-api-" + $clusterName + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + Start-Sleep -Seconds 2 + } + + # Matching url: cerebral-simulator-service + $matchingServices = $services.items | Where-Object { + $_.metadata.name -eq 'cerebral-simulator-service' -and + $_.spec.ports.port -contains 8001 + } + $backendApiIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($backendApiIp in $backendApiIps) { + $output = "http://${publicIPAddress}:8001/apidocs" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("cerebral-simulator-" + $clusterName + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + Start-Sleep -Seconds 2 + } + + # Matching url: footfall-ai-api + $matchingServices = $services.items | Where-Object { + $_.metadata.name -eq 'footfall-ai-api' -and + $_.spec.ports.port -contains 5000 + } + $backendApiIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($backendApiIp in $backendApiIps) { + $output = "http://${publicIPAddress}:5000" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("footfall-ai-api-" + $clusterName + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + Start-Sleep -Seconds 2 + } + + # Matching url: main-ui + $matchingServices = $services.items | Where-Object { + $_.metadata.name -eq 'main-ui' -and + $_.spec.ports.port -contains 8080 + } + $backendApiIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($backendApiIp in $backendApiIps) { + $output = "http://${publicIPAddress}:8080/" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("main-ui-" + $clusterName + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + Start-Sleep -Seconds 2 + } + + # Matching url: InfluxDB + $matchingServices = $services.items | Where-Object { + $_.metadata.name -eq 'InfluxDB' -and + $_.spec.ports.port -contains 8086 + } + $backendApiIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($backendApiIp in $backendApiIps) { + $output = "http://${publicIPAddress}:8086" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("InfluxDB-" + $clusterName + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + Start-Sleep -Seconds 2 + } + + # Matching url: Shopper Insights API + $matchingServices = $services.items | Where-Object { + $_.metadata.name -eq 'shopper-insights-api' -and + $_.spec.ports.port -contains 5001 + } + $backendApiIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($backendApiIp in $backendApiIps) { + $output = "http://${publicIPAddress}:5001" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("Shopper-Insights-API-" + $clusterName + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + Start-Sleep -Seconds 2 + } + + # Matching url: Grafana + # Replace matching value in the Bookmarks file + $output = "http://${publicIPAddress}:3000" + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("Grafana-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + Start-Sleep -Seconds 2 + } + Start-Sleep -Seconds 2 + + Copy-Item -Path $bookmarksFileName -Destination $edgeBookmarksPath -Force + + ############################################################## + # Pinning important directories to Quick access + ############################################################## + Write-Host "[$(Get-Date -Format t)] INFO: Pinning important directories to Quick access (Step 16/17)" -ForegroundColor DarkGreen + $quickAccess = new-object -com shell.application + $quickAccess.Namespace($AgConfig.AgDirectories.AgDir).Self.InvokeVerb("pintohome") + $quickAccess.Namespace($AgConfig.AgDirectories.AgLogsDir).Self.InvokeVerb("pintohome") +} + +function Set-GPU-Operator { + Write-Host "Starting GPU Operator installation..." -ForegroundColor Gray + + # Add the NVIDIA Helm repository + Write-Host "Adding NVIDIA Helm repository..." -ForegroundColor Gray + helm repo add nvidia https://helm.ngc.nvidia.com/nvidia + helm repo update + + # Loop through each cluster and install the GPU operator + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + Write-Host "Switching context to cluster: $clusterName" -ForegroundColor Gray + kubectx $clusterName + + # Create the namespace for the GPU operator + Write-Host "Creating GPU operator namespace in $clusterName..." -ForegroundColor Gray + kubectl create namespace gpu-operator -o yaml --dry-run=client | kubectl apply -f - + + # Apply the time-slicing configuration YAML + Write-Host "Applying time-slicing configuration to $clusterName..." -ForegroundColor Gray + kubectl apply -f "jumpstart-apps/agora/contoso_hypermarket/charts/gpu-operator/time-slicing-config.yaml" -n gpu-operator + + # Install the GPU operator using Helm + Write-Host "Installing GPU operator in $clusterName..." -ForegroundColor Gray + helm install --wait --generate-name ` + -n gpu-operator ` + nvidia/gpu-operator ` + --create-namespace ` + --values jumpstart-apps\agora\contoso_hypermarket\charts\gpu-operator\values.yaml + + Write-Host "GPU operator installation completed on $clusterName." -ForegroundColor Green + } + + Write-Host "GPU operator installation completed successfully on all clusters." -ForegroundColor Green +} + +# Function to set the Azure Data Studio connections +function Set-AzureDataStudioConnections { + param ( + [PSCustomObject[]]$dbConnections + ) + + # Creating endpoints file + Write-Host "`n" + Write-Header "Creating SQL Server connections in Azure Data Studio " + Write-Host "`n" + + $settingsContent = @" +{ + "workbench.enablePreviewFeatures": true, + "datasource.connectionGroups": [ + { + "name": "ROOT", + "id": "C777F06B-202E-4480-B475-FA416154D458" + } + ], + "datasource.connections": [ + {{DB_CONNECTION_LIST}} + ], + "window.zoomLevel": 2 +} +"@ + + $dbConnectionsJson = "" + $index = 0 + foreach($connection in $dbConnections) { + $dagConnection = @" +{ + "options": { + "connectionName": "$($connection.sitename)", + "server": "$($connection.server)", + "database": "", + "authenticationType": "SqlLogin", + "user": "$($connection.username)", + "password": "$($connection.password)", + "applicationName": "azdata", + "groupId": "C777F06B-202E-4480-B475-FA416154D458", + "databaseDisplayName": "", + "trustServerCertificate": true + }, + "groupId": "C777F06B-202E-4480-B475-FA416154D458", + "providerName": "MSSQL", + "savePassword": true, + "id": "ac333479-a04b-436b-88ab-3b314a201295" +} +"@ + $dbConnectionsJson += $dagConnection + + if ($index -lt $dbConnections.Count - 1) { + $dbConnectionsJson += ",`n" + } + else { + $dbConnectionsJson += "`n" + } + $index += 1 + } + + $settingsContent = $settingsContent -replace '{{DB_CONNECTION_LIST}}', $dbConnectionsJson + + $settingsFilePath = "$Env:APPDATA\azuredatastudio\User\settings.json" + + # Verify file path and create new one if not found + if (-not (Test-Path -Path $settingsFilePath)){ + New-Item -ItemType File -Path $settingsFilePath -Force + } + + $settingsContent | Set-Content -Path $settingsFilePath +} + +# Function to set the SQL Server connections file and Azure Data Studio connections shortcuts +function Set-DatabaseConnectionsShortcuts { + # Creating endpoints file + Write-Host "`n" + Write-Header "Creating Database Endpoints file Desktop shortcut" + Write-Host "`n" + + $filename = "DatabaseConnectionEndpoints.txt" + $file = New-Item -Path $AgConfig.AgDirectories.AgDir -Name $filename -ItemType "file" -Force + $Endpoints = $file.FullName + Add-Content $Endpoints "======================================================================" + Add-Content $Endpoints "" + + $dbConnections = @() + + # Get SQL server service IP and the port + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $clusterName = $cluster.Name.ToLower() + kubectx $clusterName + + # Get Loadbalancer IP and target port + $sqlService = kubectl get service mssql-service -n contoso-hypermarket -o json | ConvertFrom-Json + $endPoint = "$($sqlService.spec.loadBalancerIP),$($sqlService.spec.ports.targetPort)" + Add-Content $Endpoints "SQL Server external endpoint for $clusterName cluster:" + $endPoint | Add-Content $Endpoints + + # Get SQL server username and password + $secret = kubectl get secret azure-sqlpassword-secret -n contoso-hypermarket -o json | ConvertFrom-Json + $password = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($secret.data.'azure-sqlpassword-secret')) + Add-Content $Endpoints "Username: SA, Password: $password" + Add-Content $Endpoints "" + Add-Content $Endpoints "" + + $siteName = [cultureinfo]::GetCultureInfo("en-US").TextInfo.ToTitleCase($clusterName) + $dbConnectionInfo = @{ + sitename = "$siteName" + server = "$endPoint" + username="SA" + password = "$password" + } + + # Add to the connection list + $dbConnections += $dbConnectionInfo + } + + Add-Content $Endpoints "======================================================================" + Add-Content $Endpoints "" + + $TargetFile = $Endpoints + $ShortcutFile = "C:\Users\$env:adminUsername\Desktop\SQL Server Endpoints.lnk" + $WScriptShell = New-Object -ComObject WScript.Shell + $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile) + $Shortcut.TargetPath = $TargetFile + $Shortcut.Save() + + # Create Azure Data Studio connection + Set-AzureDataStudioConnections -dbConnections $dbConnections +} diff --git a/azure_jumpstart_ag/artifacts/PowerShell/Modules/contoso_motors.psm1 b/azure_jumpstart_ag/artifacts/PowerShell/Modules/contoso_motors.psm1 new file mode 100644 index 0000000000..ed4fee4ed1 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/PowerShell/Modules/contoso_motors.psm1 @@ -0,0 +1,309 @@ +function Deploy-MotorsConfigs { + Write-Host "[$(Get-Date -Format t)] INFO: Configuring OVMS prerequisites on Kubernetes nodes." -ForegroundColor Gray + $VMs = (Get-VM).Name + foreach ($VM in $VMs) { + Invoke-Command -VMName $VM -Credential $Credentials -ScriptBlock { + Invoke-AksEdgeNodeCommand -NodeType Linux -command "curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.27.0/install.sh | bash -s v0.27.0" + } + kubectx $VM.ToLower() + kubectl create -f https://operatorhub.io/install/ovms-operator.yaml + } + + # Loop through the clusters and deploy the configs in AppConfig hashtable in AgConfig-contoso-motors.psd + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + Start-Job -Name gitops -ScriptBlock { + $AgConfig = $using:AgConfig + $cluster = $using:cluster + $namingGuid = $using:namingGuid + $resourceGroup = $using:resourceGroup + $appClonedRepo = $using:appUpstreamRepo + $appsRepo = $using:appsRepo + + $AgConfig.AppConfig.GetEnumerator() | sort-object -Property @{Expression = { $_.value.Order }; Ascending = $true } | ForEach-Object { + $app = $_ + $clusterName = $cluster.value.ArcClusterName + "-$namingGuid" + $branch = $cluster.value.Branch.ToLower() + $configName = $app.value.GitOpsConfigName.ToLower() + $namespace = $app.value.Namespace + $appName = $app.Value.KustomizationName + $appPath = $app.Value.KustomizationPath + $retryCount = 0 + $maxRetries = 2 + + Write-Host "[$(Get-Date -Format t)] INFO: Creating GitOps config for $configName on $($cluster.Value.ArcClusterName+"-$namingGuid")" -ForegroundColor Gray + $type = "connectedClusters" + + # Wait for Kubernetes API server to become available + $apiServer = kubectl config view --context $cluster.Name.ToLower() --minify -o jsonpath='{.clusters[0].cluster.server}' + $apiServerAddress = $apiServer -replace '.*https://| .*$' + $apiServerFqdn = ($apiServerAddress -split ":")[0] + $apiServerPort = ($apiServerAddress -split ":")[1] + + do { + $result = Test-NetConnection -ComputerName $apiServerFqdn -Port $apiServerPort -WarningAction SilentlyContinue + if ($result.TcpTestSucceeded) { + break + } + else { + Start-Sleep -Seconds 5 + } + } while ($true) + + + az k8s-configuration flux create ` + --cluster-name $clusterName ` + --resource-group $resourceGroup ` + --name $configName ` + --cluster-type $type ` + --scope cluster ` + --url $appClonedRepo ` + --branch $branch ` + --sync-interval 3s ` + --kustomization name=$appName path=$appPath prune=true retry_interval=1m ` + --timeout 10m ` + --namespace $namespace ` + --only-show-errors ` + 2>&1 | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + + do { + $configStatus = $(az k8s-configuration flux show --name $configName --cluster-name $clusterName --cluster-type $type --resource-group $resourceGroup -o json 2>$null) | convertFrom-JSON + if ($configStatus.ComplianceState -eq "Compliant") { + Write-Host "[$(Get-Date -Format t)] INFO: GitOps configuration $configName is ready on $clusterName" -ForegroundColor DarkGreen | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + } + else { + if ($configStatus.ComplianceState -ne "Non-compliant") { + Start-Sleep -Seconds 20 + } + elseif ($configStatus.ComplianceState -eq "Non-compliant" -and $retryCount -lt $maxRetries) { + Start-Sleep -Seconds 20 + $configStatus = $(az k8s-configuration flux show --name $configName --cluster-name $clusterName --cluster-type $type --resource-group $resourceGroup -o json 2>$null) | convertFrom-JSON + if ($configStatus.ComplianceState -eq "Non-compliant" -and $retryCount -lt $maxRetries) { + $retryCount++ + Write-Host "[$(Get-Date -Format t)] INFO: Attempting to re-install $configName on $clusterName" -ForegroundColor Gray | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + Write-Host "[$(Get-Date -Format t)] INFO: Deleting $configName on $clusterName" -ForegroundColor Gray | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + az k8s-configuration flux delete ` + --resource-group $resourceGroup ` + --cluster-name $clusterName ` + --cluster-type $type ` + --name $configName ` + --force ` + --yes ` + --only-show-errors ` + 2>&1 | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + + Start-Sleep -Seconds 10 + Write-Host "[$(Get-Date -Format t)] INFO: Re-creating $configName on $clusterName" -ForegroundColor Gray | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + + az k8s-configuration flux create ` + --cluster-name $clusterName ` + --resource-group $resourceGroup ` + --name $configName ` + --cluster-type $type ` + --scope cluster ` + --url $appClonedRepo ` + --branch $branch ` + --sync-interval 3s ` + --kustomization name=$appName path=$appPath prune=true ` + --timeout 30m ` + --namespace $namespace ` + --only-show-errors ` + 2>&1 | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + } + } + elseif ($configStatus.ComplianceState -eq "Non-compliant" -and $retryCount -eq $maxRetries) { + Write-Host "[$(Get-Date -Format t)] ERROR: GitOps configuration $configName has failed on $clusterName. Exiting..." -ForegroundColor White -BackgroundColor Red | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + break + } + } + } until ($configStatus.ComplianceState -eq "Compliant") + } + } + } + + while ($(Get-Job -Name gitops).State -eq 'Running') { + #Write-Host "[$(Get-Date -Format t)] INFO: Waiting for GitOps configuration to complete on all clusters...waiting 60 seconds" -ForegroundColor Gray + Receive-Job -Name gitops -WarningAction SilentlyContinue + Start-Sleep -Seconds 60 + } + + Get-Job -name gitops | Remove-Job + Write-Host "[$(Get-Date -Format t)] INFO: GitOps configuration complete." -ForegroundColor Green + Write-Host +} + +function Deploy-MQTTSimulator { + param ( + [array]$mqttIpArray + ) + + $mqsimulatorfile = "$AgToolsDir\mqtt_simulator.yml" + + $clusters = $AgConfig.SiteConfig.GetEnumerator() + + foreach ($cluster in $clusters) { + $clusterName = $cluster.Name.ToLower() + Copy-Item $mqsimulatorfile "$AgToolsDir\mqtt_simulator_$clusterName.yml" -Force + $simualtorConfig = "$AgToolsDir\mqtt_simulator_$clusterName.yml" + $mqttIp = $mqttIpArray | Where-Object { $_.cluster -eq $clusterName } | Select-Object -ExpandProperty ip + Write-Host "[$(Get-Date -Format t)] INFO: Deploying MQTT Simulator to the $clusterName cluster" -ForegroundColor Gray + Write-Host "`n" + kubectx $clusterName + (Get-Content $simualtorConfig ) -replace 'MQTTIpPlaceholder', $mqttIp | Set-Content $simualtorConfig + netsh interface portproxy add v4tov4 listenport=1883 listenaddress=0.0.0.0 connectport=1883 connectaddress=$mqttIp + kubectl apply -f $simualtorConfig -n $aioNamespace + } +} + +# Function to deploy Azure Data Explorer dashboard reports +function Deploy-ADXDashboardReports { + ### BELOW IS AN ALTERNATIVE APPROACH TO IMPORT DASHBOARD USING README INSTRUCTIONS + $adxDashBoardsDir = $AgConfig.AgDirectories["AgAdxDashboards"] + + # Create directory if do not exist + if (-not (Test-Path -LiteralPath $adxDashBoardsDir)) { + New-Item -Path $adxDashBoardsDir -ItemType Directory -ErrorAction Stop | Out-Null #-Force + } + + #$dataEmulatorDir = $AgConfig.AgDirectories["AgDataEmulator"] + $kustoCluster = Get-AzKustoCluster -ResourceGroupName $resourceGroup -Name $adxClusterName + if ($null -ne $kustoCluster) { + $adxEndPoint = $kustoCluster.Uri + if ($null -ne $adxEndPoint -and $adxEndPoint -ne "") { + $ordersDashboardBody = (Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/adx_dashboards/adx-dashboard-contoso-motors-auto-parts.json").Content -replace '{{ADX_CLUSTER_URI}}', $adxEndPoint -replace '{{ADX_CLUSTER_NAME}}', $adxClusterName -replace '{{GITHUB_BRANCH}}', $env:githubBranch -replace '{{GITHUB_ACCOUNT}}', $env:githubAccount + Set-Content -Path "$adxDashBoardsDir\adx-dashboard-contoso-motors-auto-parts.json" -Value $ordersDashboardBody -Force -ErrorAction Ignore + } + else { + Write-Host "[$(Get-Date -Format t)] ERROR: Unable to find Azure Data Explorer endpoint from the cluster resource in the resource group." + } + } + + # Create EventHub environment variables + $eventHubNamespace = (az eventhubs namespace list --resource-group $env:resourceGroup --query [0].name --output tsv) + if ($null -ne $eventHubNamespace) { + # Find EventHub and create connection string + $eventHub = (az eventhubs eventhub list --namespace-name $eventHubNamespace --resource-group $env:resourceGroup --query [0].name --output tsv) + + # Create authorization rule + $authRuleName = "data-emulator" + az eventhubs eventhub authorization-rule create --authorization-rule-name $authRuleName --eventhub-name $eventHub --namespace-name $eventHubNamespace --resource-group $env:resourceGroup --rights Send Listen + + # Get connection string + $connectionString = (az eventhubs eventhub authorization-rule keys list --resource-group $env:resourceGroup --namespace-name $eventHubNamespace --eventhub-name $eventHub --name $authRuleName --query primaryConnectionString --output tsv) + + # Set environment variables + [System.Environment]::SetEnvironmentVariable('EVENTHUB_CONNECTION_STRING', $connectionString, [System.EnvironmentVariableTarget]::Machine) + [System.Environment]::SetEnvironmentVariable('EVENTHUB_NAME', $eventHub, [System.EnvironmentVariableTarget]::Machine) + } + + # Create desktop icons + $AgDataEmulatorDir = $AgConfig.AgDirectories["AgDataEmulator"] + $dataEmulatorFile = "$AgDataEmulatorDir\data-emulator.py" + Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/data_emulator/data-emulator.py" -OutFile $dataEmulatorFile + if (!(Test-Path -Path $dataEmulatorFile)) { + Write-Host "Unabled to download data-emulator.py file. Please download manually from GitHub into the DataEmulator folder." + } + + $emulationScriptContent = "@echo off `r`ncmd /k `"cd /d $AgDataEmulatorDir & python data-emulator.py`"" + $emulatorLocation = "$AgDataEmulatorDir\dataemulator.cmd" + Set-Content -Path $emulatorLocation -Value $emulationScriptContent + + # Download icon file + $AgIconsDir = $AgConfig.AgDirectories["AgIconDir"] + + $iconPath = "$AgIconsDir\emulator.ico" + Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/icons/emulator.ico" -OutFile $iconPath + if (!(Test-Path -Path $iconPath)) { + Write-Host "Unabled to download emulator.ico file. Please download manually from GitHub into the icons folder." + } + + # Create desktop shortcut + $shortcutLocation = "$Env:Public\Desktop\Data Emulator.lnk" + $wScriptShell = New-Object -ComObject WScript.Shell + $shortcut = $wScriptShell.CreateShortcut($shortcutLocation) + $shortcut.TargetPath = $emulatorLocation + $shortcut.IconLocation = "$iconPath, 0" + $shortcut.WindowStyle = 8 + $shortcut.Save() + + # Install azure.eventhub python module to run data emulator + pip install azure.eventhub +} + +function Deploy-MotorsBookmarks { + $bookmarksFileName = "$AgToolsDir\Bookmarks" + $edgeBookmarksPath = "$Env:LOCALAPPDATA\Microsoft\Edge\User Data\Default" + + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + kubectx $cluster.Name.ToLower() | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + $services = kubectl get services --all-namespaces -o json | ConvertFrom-Json + + # Matching url: flask app + $matchingServices = $services.items | Where-Object { + $_.metadata.name -eq 'flask-app-service' -and + $_.spec.ports.port -contains 8888 + } + $flaskIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($flaskIp in $flaskIps) { + $output = "http://${flaskIp}:8888" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("Flask-" + $cluster.Name + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + + Start-Sleep -Seconds 2 + } + + # Matching url: Influxdb + $matchingServices = $services.items | Where-Object { + $_.metadata.name -eq 'Influxdb' -and + $_.spec.ports.port -contains 8086 + } + $influxdbIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($influxdbIp in $influxdbIps) { + $output = "http://${influxdbIp}:8086" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("Influxdb-" + $cluster.Name + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + + Start-Sleep -Seconds 2 + } + + # Matching url: prometheus + $matchingServices = $services.items | Where-Object { + $_.spec.ports.port -contains 9090 -and + $_.spec.type -eq "LoadBalancer" + } + $prometheusIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($prometheusIp in $prometheusIps) { + $output = "http://${prometheusIp}:9090" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("Prometheus-" + $cluster.Name + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + + Start-Sleep -Seconds 2 + } + } + + Start-Sleep -Seconds 2 + + Copy-Item -Path $bookmarksFileName -Destination $edgeBookmarksPath -Force + + ############################################################## + # Pinning important directories to Quick access + ############################################################## + Write-Host "[$(Get-Date -Format t)] INFO: Pinning important directories to Quick access (Step 16/17)" -ForegroundColor DarkGreen + $quickAccess = new-object -com shell.application + $quickAccess.Namespace($AgConfig.AgDirectories.AgDir).Self.InvokeVerb("pintohome") + $quickAccess.Namespace($AgConfig.AgDirectories.AgLogsDir).Self.InvokeVerb("pintohome") +} diff --git a/azure_jumpstart_ag/artifacts/PowerShell/Modules/contoso_supermarket.psm1 b/azure_jumpstart_ag/artifacts/PowerShell/Modules/contoso_supermarket.psm1 new file mode 100644 index 0000000000..3df267b869 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/PowerShell/Modules/contoso_supermarket.psm1 @@ -0,0 +1,772 @@ +function SetupSupermarketRepo { + Set-Location $AgAppsRepo + Write-Host "INFO: Checking if the $appsRepo repository is forked" -ForegroundColor Gray + $retryCount = 0 + $maxRetries = 5 + do { + $forkExists = $false + try { + $response = Invoke-RestMethod -Uri "$gitHubAPIBaseUri/repos/$githubUser/$appsRepo" + if ($response) { + write-host "INFO: Fork exists....Proceeding" -ForegroundColor Gray + $forkExists = $true + } + } + catch { + if ($retryCount -lt $maxRetries) { + Write-Host "ERROR: $githubUser/$appsRepo Fork doesn't exist, please fork https://github.com/microsoft/jumpstart-agora-apps to proceed (attempt $retryCount/$maxRetries) . . . waiting 60 seconds" -ForegroundColor Red + $retryCount++ + $forkExists = $false + start-sleep -Seconds 60 + } + else { + Write-Host "[$(Get-Date -Format t)] ERROR: Retry limit reached, $githubUser/$appsRepo Fork doesn't exist. Exiting." -ForegroundColor Red + exit + } + } + } until ($forkExists -eq $true) + + Write-Host "INFO: Checking if the GitHub access token is valid." -ForegroundColor Gray + do { + $response = gh auth status 2>&1 + if ($response -match "authentication failed") { + write-host "ERROR: The GitHub Personal access token is not valid" -ForegroundColor Red + Write-Host "INFO: Please try to re-generate the personal access token and provide it here (https://aka.ms/AgoraPreReqs): " + do { + $githubPAT = Read-Host "GitHub personal access token" + } while ($githubPAT -eq "") + } + } until ( + $response -notmatch "authentication failed" + ) + + Write-Host "INFO: The GitHub Personal access token is valid. Proceeding." -ForegroundColor DarkGreen + $Env:GITHUB_TOKEN = $githubPAT.Trim() + [System.Environment]::SetEnvironmentVariable('GITHUB_TOKEN', $githubPAT.Trim(), [System.EnvironmentVariableTarget]::Machine) + + Write-Host "INFO: Checking if the personal access token is assigned on the $githubUser/$appsRepo Fork" -ForegroundColor Gray + $headers = @{ + Authorization = "token $githubPat" + "Content-Type" = "application/json" + } + $retryCount = 0 + $maxRetries = 5 + $uri = "$gitHubAPIBaseUri/repos/$githubUser/$appsRepo/actions/secrets" + do { + try { + $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers + Write-Host "INFO: Personal access token is assigned on $githubUser/$appsRepo fork" -ForegroundColor DarkGreen + $PatAssigned = $true + } + catch { + if ($retryCount -lt $maxRetries) { + Write-Host "ERROR: Personal access token is not assigned on $githubUser/$appsRepo fork. Please assign the personal access token to your fork (https://aka.ms/AgoraPreReqs) (attempt $retryCount/$maxRetries).....waiting 60 seconds" -ForegroundColor Red + $PatAssigned = $false + $retryCount++ + start-sleep -Seconds 60 + } + else { + Write-Host "[$(Get-Date -Format t)] ERROR: Retry limit reached, the personal access token is not assigned to $githubUser/$appsRepo. Exiting." -ForegroundColor Red + exit + } + } + } until ($PatAssigned -eq $true) + + + Write-Host "INFO: Cloning the GitHub repository locally" -ForegroundColor Gray + git clone "https://$githubPat@github.com/$githubUser/$appsRepo.git" "$AgAppsRepo\$appsRepo" + Set-Location "$AgAppsRepo\$appsRepo" + + Write-Host "INFO: Verifying 'Administration' permissions" -ForegroundColor Gray + $retryCount = 0 + $maxRetries = 5 + + $body = @{ + required_status_checks = $null + enforce_admins = $false + required_pull_request_reviews = @{ + required_approving_review_count = 0 + } + dismiss_stale_reviews = $true + restrictions = $null + } | ConvertTo-Json + + do { + try { + $response = Invoke-WebRequest -Uri "$gitHubAPIBaseUri/repos/$githubUser/$appsRepo/branches/main/protection" -Method Put -Headers $headers -Body $body -ContentType "application/json" + } + catch { + if ($retryCount -lt $maxRetries) { + Write-Host "ERROR: The GitHub Personal access token doesn't seem to have 'Administration' write permissions, please assign the right permissions (https://aka.ms/AgoraPreReqs) (attempt $retryCount/$maxRetries)...waiting 60 seconds" -ForegroundColor Red + $retryCount++ + start-sleep -Seconds 60 + } + else { + Write-Host "[$(Get-Date -Format t)] ERROR: Retry limit reached, the personal access token doesn't have 'Administration' write permissions assigned. Exiting." -ForegroundColor Red + exit + } + } + } until ($response) + Write-Host "INFO: 'Administration' write permissions verified" -ForegroundColor DarkGreen + + + Write-Host "INFO: Checking if there are existing branch protection policies" -ForegroundColor Gray + $protectedBranches = Invoke-RestMethod -Uri "$gitHubAPIBaseUri/repos/$githubUser/$appsRepo/branches?protected=true" -Method GET -Headers $headers + foreach ($branch in $protectedBranches) { + $branchName = $branch.name + $deleteProtectionUrl = "$gitHubAPIBaseUri/repos/$githubUser/$appsRepo/branches/$branchName/protection" + Invoke-RestMethod -Uri $deleteProtectionUrl -Headers $headers -Method Delete + Write-Host "INFO: Deleted protection policy for branch: $branchName" -ForegroundColor Gray + } + + Write-Host "INFO: Pulling latests changes to GitHub repository" -ForegroundColor Gray + git config --global user.email "dev@agora.com" + git config --global user.name "Agora Dev" + git remote add upstream "$appUpstreamRepo.git" + git fetch upstream + git checkout main + git reset --hard upstream/main + git push origin main -f + git pull + git remote remove upstream + git remote add upstream "$appClonedRepo.git" + + Write-Host "INFO: Creating GitHub workflows" -ForegroundColor Gray + New-Item -ItemType Directory ".github/workflows" -Force + $githubApiUrl = "$gitHubAPIBaseUri/repos/$githubAccount/azure_arc/contents/azure_jumpstart_ag/artifacts/workflows?ref=$githubBranch" + $response = Invoke-RestMethod -Uri $githubApiUrl + $fileUrls = $response | Where-Object { $_.type -eq "file" } | Select-Object -ExpandProperty download_url + $fileUrls | ForEach-Object { + $fileName = $_.Substring($_.LastIndexOf("/") + 1) + $outputFile = Join-Path "$AgAppsRepo\$appsRepo\.github\workflows" $fileName + Invoke-RestMethod -Uri $_ -OutFile $outputFile + } + git add . + git commit -m "Pushing GitHub Actions to apps fork" + git push + Start-Sleep -Seconds 20 + + Write-Host "INFO: Verifying 'Secrets' permissions" -ForegroundColor Gray + $retryCount = 0 + $maxRetries = 5 + do { + $response = gh secret set "test" -b "test" 2>&1 + if ($response -match "error") { + if ($retryCount -eq $maxRetries) { + Write-Host "[$(Get-Date -Format t)] ERROR: Retry limit reached, the personal access token doesn't have 'Secrets' write permissions assigned. Exiting." -ForegroundColor Red + exit + } + else { + $retryCount++ + write-host "ERROR: The GitHub Personal access token doesn't seem to have 'Secrets' write permissions, please assign the right permissions (https://aka.ms/AgoraPreReqs) (attempt $retryCount/$maxRetries)...waiting 60 seconds" -ForegroundColor Red + Start-Sleep -Seconds 60 + } + } + } while ($response -match "error" -or $retryCount -ge $maxRetries) + gh secret delete test + Write-Host "INFO: 'Secrets' write permissions verified" -ForegroundColor DarkGreen + + Write-Host "INFO: Verifying 'Actions' permissions" -ForegroundColor Gray + $retryCount = 0 + $maxRetries = 5 + do { + $response = gh workflow enable update-files.yml 2>&1 + if ($response -match "failed") { + if ($retryCount -eq $maxRetries) { + Write-Host "[$(Get-Date -Format t)] ERROR: Retry limit reached, the personal access token doesn't have 'Actions' write permissions assigned. Exiting." -ForegroundColor Red + exit + } + else { + $retryCount++ + write-host "ERROR: The GitHub Personal access token doesn't seem to have 'Actions' write permissions, please assign the right permissions (https://aka.ms/AgoraPreReqs) (attempt $retryCount/$maxRetries)...waiting 60 seconds" -ForegroundColor Red + Start-Sleep -Seconds 60 + } + } + } while ($response -match "failed" -or $retryCount -ge $maxRetries) + Write-Host "INFO: 'Actions' write permissions verified" -ForegroundColor DarkGreen + + write-host "INFO: Creating GitHub secrets" -ForegroundColor Gray + Write-Host "INFO: Getting Cosmos DB access key" -ForegroundColor Gray + Write-Host "INFO: Adding GitHub secrets to apps fork" -ForegroundColor Gray + gh api -X PUT "/repos/$githubUser/$appsRepo/actions/permissions/workflow" -F can_approve_pull_request_reviews=true + gh repo set-default "$githubUser/$appsRepo" + gh secret set "SPN_CLIENT_ID" -b $spnClientID + gh secret set "SPN_CLIENT_SECRET" -b $spnClientSecret + gh secret set "ACR_NAME" -b $acrName + gh secret set "PAT_GITHUB" -b $githubPat + gh secret set "COSMOS_DB_ENDPOINT" -b $cosmosDBEndpoint + gh secret set "SPN_TENANT_ID" -b $spnTenantId + + Write-Host "INFO: Updating ACR name and Cosmos DB endpoint in all branches" -ForegroundColor Gray + gh workflow run update-files.yml + while ($workflowStatus.status -ne "completed") { + Write-Host "INFO: Waiting for update-files workflow to complete" -ForegroundColor Gray + Start-Sleep -Seconds 10 + $workflowStatus = (gh run list --workflow=update-files.yml --json status) | ConvertFrom-Json + } + Write-Host "INFO: Starting Contoso supermarket pos application v1.0 image build" -ForegroundColor Gray + gh workflow run pos-app-initial-images-build.yml + + Write-Host "INFO: Creating GitHub branches to $appsRepo fork" -ForegroundColor Gray + $branches = $AgConfig.GitBranches + foreach ($branch in $branches) { + try { + $response = Invoke-RestMethod -Uri "$gitHubAPIBaseUri/repos/$githubUser/$appsRepo/branches/$branch" + if ($response) { + if ($branch -ne "main") { + Write-Host "INFO: branch $branch already exists! Deleting and recreating the branch" -ForegroundColor Gray + git push origin --delete $branch + git branch -d $branch + git fetch origin + git checkout main + git pull origin main + git checkout -b $branch main + git pull origin main + git push --set-upstream origin $branch + } + } + } + catch { + Write-Host "INFO: Creating $branch branch" -ForegroundColor Gray + git fetch origin + git checkout main + git pull origin main + git checkout -b $branch main + git pull origin main + git push --set-upstream origin $branch + } + } + Write-Host "INFO: Cleaning up any other branches" -ForegroundColor Gray + $existingBranches = gh api "repos/$githubUser/$appsRepo/branches" | ConvertFrom-Json + $branches = $AgConfig.GitBranches + foreach ($branch in $existingBranches) { + if ($branches -notcontains $branch.name) { + $branchToDelete = $branch.name + git push origin --delete $branchToDelete + } + } + + Write-Host "INFO: Switching to main branch" -ForegroundColor Gray + git checkout main + + Write-Host "INFO: Adding branch protection policies for all branches" -ForegroundColor Gray + foreach ($branch in $branches) { + Write-Host "INFO: Adding branch protection policies for $branch branch" -ForegroundColor Gray + $headers = @{ + "Authorization" = "Bearer $githubPat" + "Accept" = "application/vnd.github+json" + } + $body = @{ + required_status_checks = $null + enforce_admins = $false + required_pull_request_reviews = @{ + required_approving_review_count = 0 + } + dismiss_stale_reviews = $true + restrictions = $null + } | ConvertTo-Json + + Invoke-WebRequest -Uri "$gitHubAPIBaseUri/repos/$githubUser/$appsRepo/branches/$branch/protection" -Method Put -Headers $headers -Body $body -ContentType "application/json" + } + Write-Host "INFO: GitHub repo configuration complete!" -ForegroundColor Green + Write-Host +} + +function Deploy-AzureIOTHub { + if ($githubUser -ne "microsoft") { + $iotHubHostName = $Env:iotHubHostName + $iotHubName = $iotHubHostName.replace(".azure-devices.net", "") + $sites = $AgConfig.SiteConfig.Values + Write-Host "[$(Get-Date -Format t)] INFO: Create an Azure IoT device for each site" -ForegroundColor Gray + foreach ($site in $sites) { + foreach ($device in $site.IoTDevices) { + $deviceId = "$device-$($site.FriendlyName)" + Add-AzIotHubDevice -ResourceGroupName $resourceGroup -IotHubName $iotHubName -DeviceId $deviceId -EdgeEnabled | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\IoT.log") + } + } + Write-Host "[$(Get-Date -Format t)] INFO: Azure IoT Hub configuration complete!" -ForegroundColor Green + Write-Host + } + else { + Write-Host "[$(Get-Date -Format t)] ERROR: You have to fork the jumpstart-agora-apps repository!" -ForegroundColor Red + } + + ### BELOW IS AN ALTERNATIVE APPROACH TO IMPORT DASHBOARD USING README INSTRUCTIONS + $adxDashBoardsDir = $AgConfig.AgDirectories["AgAdxDashboards"] + $dataEmulatorDir = $AgConfig.AgDirectories["AgDataEmulator"] + $kustoCluster = Get-AzKustoCluster -ResourceGroupName $resourceGroup -Name $adxClusterName + if ($null -ne $kustoCluster) { + $adxEndPoint = $kustoCluster.Uri + if ($null -ne $adxEndPoint -and $adxEndPoint -ne "") { + $ordersDashboardBody = (Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/adx_dashboards/adx-dashboard-orders-payload.json").Content -replace '{{ADX_CLUSTER_URI}}', $adxEndPoint -replace '{{ADX_CLUSTER_NAME}}', $adxClusterName + Set-Content -Path "$adxDashBoardsDir\adx-dashboard-orders-payload.json" -Value $ordersDashboardBody -Force -ErrorAction Ignore + $iotSensorsDashboardBody = (Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/adx_dashboards/adx-dashboard-iotsensor-payload.json") -replace '{{ADX_CLUSTER_URI}}', $adxEndPoint -replace '{{ADX_CLUSTER_NAME}}', $adxClusterName + Set-Content -Path "$adxDashBoardsDir\adx-dashboard-iotsensor-payload.json" -Value $iotSensorsDashboardBody -Force -ErrorAction Ignore + } + else { + Write-Host "[$(Get-Date -Format t)] ERROR: Unable to find Azure Data Explorer endpoint from the cluster resource in the resource group." + } + } + + # Download DataEmulator.zip into Agora folder and unzip + $emulatorPath = "$dataEmulatorDir\DataEmulator.zip" + Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/data_emulator/DataEmulator.zip" -OutFile $emulatorPath + + # Unzip DataEmulator.zip to copy DataEmulator exe and config file to generate sample data for dashboards + if (Test-Path -Path $emulatorPath) { + Expand-Archive -Path "$emulatorPath" -DestinationPath "$dataEmulatorDir" -ErrorAction SilentlyContinue -Force + } + + # Download products.json and stores.json file to use in Data Emulator + $productsJsonPath = "$dataEmulatorDir\products.json" + Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/data_emulator/products.json" -OutFile $productsJsonPath + if (!(Test-Path -Path $productsJsonPath)) { + Write-Host "Unabled to download products.json file. Please download manually from GitHub into the data_emulator folder." + } + + $storesJsonPath = "$dataEmulatorDir\stores.json" + Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/data_emulator/stores.json" -OutFile $storesJsonPath + if (!(Test-Path -Path $storesJsonPath)) { + Write-Host "Unabled to download stores.json file. Please download manually from GitHub into the data_emulator folder." + } + + # Download icon file + $iconPath = "$AgIconsDir\emulator.ico" + Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/icons/emulator.ico" -OutFile $iconPath + if (!(Test-Path -Path $iconPath)) { + Write-Host "Unabled to download emulator.ico file. Please download manually from GitHub into the icons folder." + } + + # Create desktop shortcut + $shortcutLocation = "$Env:Public\Desktop\Data Emulator.lnk" + $wScriptShell = New-Object -ComObject WScript.Shell + $shortcut = $wScriptShell.CreateShortcut($shortcutLocation) + $shortcut.TargetPath = "$dataEmulatorDir\DataEmulator.exe" + $shortcut.IconLocation = "$iconPath, 0" + $shortcut.WindowStyle = 7 + $shortcut.Save() +} + +function Deploy-K8sImagesCache { + if ($Env:scenario -eq "contoso_supermarket") { + Write-Host "[$(Get-Date -Format t)] INFO: Caching contoso-supermarket images on all clusters" -ForegroundColor Gray + while ($workflowStatus.status -ne "completed") { + Write-Host "INFO: Waiting for pos-app-initial-images-build workflow to complete" -ForegroundColor Gray + Start-Sleep -Seconds 10 + $workflowStatus = (gh run list --workflow=pos-app-initial-images-build.yml --json status) | ConvertFrom-Json + } + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + $branch = $cluster.Name.ToLower() + $context = $cluster.Name.ToLower() + $applicationName = "contoso-supermarket" + $imageTag = "v1.0" + $imagePullSecret = "acr-secret" + $namespace = "images-cache" + if ($branch -eq "chicago") { + $branch = "canary" + } + if ($branch -eq "seattle") { + $branch = "production" + } + Save-K8sImage -applicationName $applicationName -imageName "contosoai" -imageTag $imageTag -namespace $namespace -imagePullSecret $imagePullSecret -branch $branch -acrName $acrName -context $context + Save-K8sImage -applicationName $applicationName -imageName "pos" -imageTag $imageTag -namespace $namespace -imagePullSecret $imagePullSecret -branch $branch -acrName $acrName -context $context + Save-K8sImage -applicationName $applicationName -imageName "pos-cloudsync" -imageTag $imageTag -namespace $namespace -imagePullSecret $imagePullSecret -branch $branch -acrName $acrName -context $context + Save-K8sImage -applicationName $applicationName -imageName "queue-monitoring-backend" -imageTag $imageTag -namespace $namespace -imagePullSecret $imagePullSecret -branch $branch -acrName $acrName -context $context + Save-K8sImage -applicationName $applicationName -imageName "queue-monitoring-frontend" -imageTag $imageTag -namespace $namespace -imagePullSecret $imagePullSecret -branch $branch -acrName $acrName -context $context + } + } +} + +function Save-K8sImage { + param ( + [Parameter(Mandatory = $True, + ValueFromPipeline = $True, + ValueFromPipelineByPropertyName = $True)] + [string]$applicationName, + [Parameter(Mandatory = $True, + ValueFromPipeline = $True, + ValueFromPipelineByPropertyName = $True)] + [string]$imageName, + [Parameter(Mandatory = $True)] + [string]$imageTag, + [Parameter(Mandatory = $True)] + [string]$namespace, + [Parameter(Mandatory = $True)] + [string]$imagePullSecret, + [Parameter(Mandatory = $True, + ValueFromPipeline = $True, + ValueFromPipelineByPropertyName = $True)] + [string]$branch, + [Parameter(Mandatory = $True)] + [string]$acrName, + [Parameter(Mandatory = $True, + ValueFromPipeline = $True, + ValueFromPipelineByPropertyName = $True)] + [string]$context + ) + $imageToPull = "${acrName}.azurecr.io/${branch}/${applicationName}/${imageName}:${imageTag}" +$yaml = @" +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: images-cache-$imageName +spec: + selector: + matchLabels: + app: images-cache-$imageName + template: + metadata: + labels: + app: images-cache-$imageName + spec: + containers: + - image: $imageToPull + imagePullPolicy: IfNotPresent + name: images-cache-$imageName + imagePullSecrets: + - name: $imagePullSecret +"@ + $yaml | kubectl apply -f - --context $context -n $namespace + +} +function Get-GitHubFiles ($githubApiUrl, $folderPath, [Switch]$excludeFolders) { + # Force TLS 1.2 for connections to prevent TLS/SSL errors + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + + $response = Invoke-RestMethod -Uri $githubApiUrl + $fileUrls = $response | Where-Object { $_.type -eq "file" } | Select-Object -ExpandProperty download_url + $fileUrls | ForEach-Object { + $fileName = $_.Substring($_.LastIndexOf("/") + 1) + $outputFile = Join-Path $folderPath $fileName + Invoke-RestMethod -Uri $_ -OutFile $outputFile + } + + If (-not $excludeFolders) { + $response | Where-Object { $_.type -eq "dir" } | ForEach-Object { + $folderName = $_.name + $path = Join-Path $folderPath $folderName + New-Item $path -ItemType Directory -Force -ErrorAction Continue + Get-GitHubFiles -githubApiUrl $_.url -folderPath $path + } + } +} +function Deploy-supermarketConfigs { + Write-Host "[$(Get-Date -Format t)] INFO: Cleaning up images-cache namespace on all clusters" -ForegroundColor Gray + # Cleaning up images-cache namespace on all clusters + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + Start-Job -Name images-cache-cleanup -ScriptBlock { + $cluster = $using:cluster + $clusterName = $cluster.Name.ToLower() + Write-Host "[$(Get-Date -Format t)] INFO: Deleting images-cache namespace on cluster $clusterName" -ForegroundColor Gray + kubectl delete namespace "images-cache" --context $clusterName + } + } + + # TODO - this looks app-specific so should perhaps be moved to the app loop + while ($workflowStatus.status -ne "completed") { + Write-Host "INFO: Waiting for pos-app-initial-images-build workflow to complete" -ForegroundColor Gray + Start-Sleep -Seconds 10 + $workflowStatus = (gh run list --workflow=pos-app-initial-images-build.yml --json status) | ConvertFrom-Json + } + + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + Start-Job -Name gitops -ScriptBlock { + + Function Get-GitHubFiles ($githubApiUrl, $folderPath, [Switch]$excludeFolders) { + # Force TLS 1.2 for connections to prevent TLS/SSL errors + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + + $response = Invoke-RestMethod -Uri $githubApiUrl + $fileUrls = $response | Where-Object { $_.type -eq "file" } | Select-Object -ExpandProperty download_url + $fileUrls | ForEach-Object { + $fileName = $_.Substring($_.LastIndexOf("/") + 1) + $outputFile = Join-Path $folderPath $fileName + Invoke-RestMethod -Uri $_ -OutFile $outputFile + } + + If (-not $excludeFolders) { + $response | Where-Object { $_.type -eq "dir" } | ForEach-Object { + $folderName = $_.name + $path = Join-Path $folderPath $folderName + New-Item $path -ItemType Directory -Force -ErrorAction Continue + Get-GitHubFiles -githubApiUrl $_.url -folderPath $path + } + } + } + + $AgConfig = $using:AgConfig + $cluster = $using:cluster + $site = $cluster.Value + $siteName = $site.FriendlyName.ToLower() + $namingGuid = $using:namingGuid + $resourceGroup = $using:resourceGroup + $appClonedRepo = $using:appClonedRepo + $appsRepo = $using:appsRepo + + $AgConfig.AppConfig.GetEnumerator() | sort-object -Property @{Expression = { $_.value.Order }; Ascending = $true } | ForEach-Object { + $app = $_ + $store = $cluster.value.Branch.ToLower() + $clusterName = $cluster.value.ArcClusterName + "-$namingGuid" + $branch = $cluster.value.Branch.ToLower() + $configName = $app.value.GitOpsConfigName.ToLower() + $clusterType = $cluster.value.Type + $namespace = $app.value.Namespace + $appName = $app.Value.KustomizationName + $appPath = $app.Value.KustomizationPath + $retryCount = 0 + $maxRetries = 2 + + Write-Host "[$(Get-Date -Format t)] INFO: Creating GitOps config for $configName on $($cluster.Value.ArcClusterName+"-$namingGuid")" -ForegroundColor Gray + if ($clusterType -eq "AKS") { + $type = "managedClusters" + $clusterName = $cluster.value.ArcClusterName + } + else { + $type = "connectedClusters" + } + if ($branch -eq "main") { + $store = "dev" + } + + # Wait for Kubernetes API server to become available + $apiServer = kubectl config view --context $cluster.Name.ToLower() --minify -o jsonpath='{.clusters[0].cluster.server}' + $apiServerAddress = $apiServer -replace '.*https://| .*$' + $apiServerFqdn = ($apiServerAddress -split ":")[0] + $apiServerPort = ($apiServerAddress -split ":")[1] + + do { + $result = Test-NetConnection -ComputerName $apiServerFqdn -Port $apiServerPort -WarningAction SilentlyContinue + if ($result.TcpTestSucceeded) { + break + } + else { + Start-Sleep -Seconds 5 + } + } while ($true) + If ($app.Value.ConfigMaps) { + # download the config files + foreach ($configMap in $app.value.ConfigMaps.GetEnumerator()) { + $repoPath = $configMap.value.RepoPath + $configPath = "$configMapDir\$appPath\config\$($configMap.Name)\$branch" + $iotHubName = $Env:iotHubHostName.replace(".azure-devices.net", "") + $gitHubUser = $Env:gitHubUser + $githubBranch = $Env:githubBranch + + New-Item -Path $configPath -ItemType Directory -Force | Out-Null + + $githubApiUrl = "https://api.github.com/repos/$gitHubUser/$appsRepo/$($repoPath)?ref=$branch" + Get-GitHubFiles -githubApiUrl $githubApiUrl -folderPath $configPath + + # replace the IoT Hub name and the SAS Tokens with the deployment specific values + # this is a one-off for the broker, but needs to be generalized if/when another app needs it + If ($configMap.Name -eq "mqtt-broker-config") { + $configFile = "$configPath\mosquitto.conf" + $update = (Get-Content $configFile -Raw) + $update = $update -replace "Ag-IotHub-\w*", $iotHubName + + foreach ($device in $site.IoTDevices) { + $deviceId = "$device-$($site.FriendlyName)" + $deviceSASToken = $(az iot hub generate-sas-token --device-id $deviceId --hub-name $iotHubName --resource-group $resourceGroup --duration (60 * 60 * 24 * 30) --query sas -o tsv --only-show-errors) + $update = $update -replace "Chicago", $site.FriendlyName + $update = $update -replace "SharedAccessSignature.*$($device).*", $deviceSASToken + } + + $update | Set-Content $configFile + } + + # create the namespace if needed + If (-not (kubectl get namespace $namespace --context $siteName)) { + kubectl create namespace $namespace --context $siteName + } + # create the configmap + kubectl create configmap $configMap.name --from-file=$configPath --namespace $namespace --context $siteName + } + } + + az k8s-configuration flux create ` + --cluster-name $clusterName ` + --resource-group $resourceGroup ` + --name $configName ` + --cluster-type $type ` + --url $appClonedRepo ` + --branch $branch ` + --sync-interval 5s ` + --kustomization name=$appName path=$appPath/$store prune=true retry_interval=1m ` + --timeout 10m ` + --namespace $namespace ` + --only-show-errors ` + 2>&1 | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + + do { + $configStatus = $(az k8s-configuration flux show --name $configName --cluster-name $clusterName --cluster-type $type --resource-group $resourceGroup -o json 2>$null) | convertFrom-JSON + if ($configStatus.ComplianceState -eq "Compliant") { + Write-Host "[$(Get-Date -Format t)] INFO: GitOps configuration $configName is ready on $clusterName" -ForegroundColor DarkGreen | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + } + else { + if ($configStatus.ComplianceState -ne "Non-compliant") { + Start-Sleep -Seconds 20 + } + elseif ($configStatus.ComplianceState -eq "Non-compliant" -and $retryCount -lt $maxRetries) { + Start-Sleep -Seconds 20 + $configStatus = $(az k8s-configuration flux show --name $configName --cluster-name $clusterName --cluster-type $type --resource-group $resourceGroup -o json 2>$null) | convertFrom-JSON + if ($configStatus.ComplianceState -eq "Non-compliant" -and $retryCount -lt $maxRetries) { + $retryCount++ + Write-Host "[$(Get-Date -Format t)] INFO: Attempting to re-install $configName on $clusterName" -ForegroundColor Gray | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + Write-Host "[$(Get-Date -Format t)] INFO: Deleting $configName on $clusterName" -ForegroundColor Gray | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + az k8s-configuration flux delete ` + --resource-group $resourceGroup ` + --cluster-name $clusterName ` + --cluster-type $type ` + --name $configName ` + --force ` + --yes ` + --only-show-errors ` + 2>&1 | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + + Start-Sleep -Seconds 10 + Write-Host "[$(Get-Date -Format t)] INFO: Re-creating $configName on $clusterName" -ForegroundColor Gray | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + + az k8s-configuration flux create ` + --cluster-name $clusterName ` + --resource-group $resourceGroup ` + --name $configName ` + --cluster-type $type ` + --url $appClonedRepo ` + --branch $branch ` + --sync-interval 5s ` + --kustomization name=$appName path=$appPath/$store prune=true ` + --timeout 30m ` + --namespace $namespace ` + --only-show-errors ` + 2>&1 | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + } + } + elseif ($configStatus.ComplianceState -eq "Non-compliant" -and $retryCount -eq $maxRetries) { + Write-Host "[$(Get-Date -Format t)] ERROR: GitOps configuration $configName has failed on $clusterName. Exiting..." -ForegroundColor White -BackgroundColor Red | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\GitOps-$clusterName.log") + break + } + } + } until ($configStatus.ComplianceState -eq "Compliant") + } + } + } + + while ($(Get-Job -Name gitops).State -eq 'Running') { + #Write-Host "[$(Get-Date -Format t)] INFO: Waiting for GitOps configuration to complete on all clusters...waiting 60 seconds" -ForegroundColor Gray + Receive-Job -Name gitops -WarningAction SilentlyContinue + Start-Sleep -Seconds 60 + } + + Get-Job -name gitops | Remove-Job + Write-Host "[$(Get-Date -Format t)] INFO: GitOps configuration complete." -ForegroundColor Green + Write-Host +} + +function Deploy-supermarketBookmarks { + $bookmarksFileName = "$AgToolsDir\Bookmarks" + $edgeBookmarksPath = "$Env:LOCALAPPDATA\Microsoft\Edge\User Data\Default" + + foreach ($cluster in $AgConfig.SiteConfig.GetEnumerator()) { + kubectx $cluster.Name.ToLower() | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + $services = kubectl get services --all-namespaces -o json | ConvertFrom-Json + + # Matching url: pos - customer + $matchingServices = $services.items | Where-Object { + $_.spec.ports.port -contains 5000 -and + $_.spec.type -eq "LoadBalancer" + } + $posIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($posIp in $posIps) { + $output = "http://$posIp" + ':5000' + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("POS-" + $cluster.Name + "-URL-Customer"), $output + $newContent | Set-Content -Path $bookmarksFileName + + Start-Sleep -Seconds 2 + } + + # Matching url: pos - manager + $matchingServices = $services.items | Where-Object { + $_.spec.ports.port -contains 81 -and + $_.spec.type -eq "LoadBalancer" + } + $posIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($posIp in $posIps) { + $output = "http://$posIp" + ':81' + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("POS-" + $cluster.Name + "-URL-Manager"), $output + $newContent | Set-Content -Path $bookmarksFileName + + Start-Sleep -Seconds 2 + } + + # Matching url: prometheus-grafana + if ($cluster.Name -eq "Staging" -or $cluster.Name -eq "Dev") { + $matchingServices = $services.items | Where-Object { + $_.metadata.name -eq 'prometheus-grafana' + } + $grafanaIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($grafanaIp in $grafanaIps) { + $output = "http://$grafanaIp" + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("Grafana-" + $cluster.Name + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + + Start-Sleep -Seconds 2 + } + } + + # Matching url: prometheus + $matchingServices = $services.items | Where-Object { + $_.spec.ports.port -contains 9090 -and + $_.spec.type -eq "LoadBalancer" + } + $prometheusIps = $matchingServices.status.loadBalancer.ingress.ip + + foreach ($prometheusIp in $prometheusIps) { + $output = "http://$prometheusIp" + ':9090' + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace ("Prometheus-" + $cluster.Name + "-URL"), $output + $newContent | Set-Content -Path $bookmarksFileName + + Start-Sleep -Seconds 2 + } + } + + # Matching url: Agora apps forked repo + $output = $appClonedRepo + $output | Out-File -Append -FilePath ($AgConfig.AgDirectories["AgLogsDir"] + "\Bookmarks.log") + + # Replace matching value in the Bookmarks file + $content = Get-Content -Path $bookmarksFileName + $newContent = $content -replace "Agora-Apps-Repo-Clone-URL", $output + $newContent = $newContent -replace "Agora-Apps-Repo-Your-Fork", "Agora Apps Repo - $githubUser" + $newContent | Set-Content -Path $bookmarksFileName + + Start-Sleep -Seconds 2 + + Copy-Item -Path $bookmarksFileName -Destination $edgeBookmarksPath -Force + + ############################################################## + # Pinning important directories to Quick access + ############################################################## + Write-Host "[$(Get-Date -Format t)] INFO: Pinning important directories to Quick access (Step 16/17)" -ForegroundColor DarkGreen + $quickAccess = new-object -com shell.application + $quickAccess.Namespace($AgConfig.AgDirectories.AgDir).Self.InvokeVerb("pintohome") + $quickAccess.Namespace($AgConfig.AgDirectories.AgLogsDir).Self.InvokeVerb("pintohome") +} diff --git a/azure_jumpstart_ag/artifacts/PowerShell/PSProfile.ps1 b/azure_jumpstart_ag/artifacts/PowerShell/PSProfile.ps1 index 40ae832111..e09d98a935 100644 --- a/azure_jumpstart_ag/artifacts/PowerShell/PSProfile.ps1 +++ b/azure_jumpstart_ag/artifacts/PowerShell/PSProfile.ps1 @@ -131,7 +131,6 @@ Function Invoke-CommandLineTool { } } - function Save-K8sImage { param ( [Parameter(Mandatory = $True, diff --git a/azure_jumpstart_ag/artifacts/PowerShell/SetupFabricWorkspace.ps1 b/azure_jumpstart_ag/artifacts/PowerShell/SetupFabricWorkspace.ps1 new file mode 100644 index 0000000000..d450a8b23c --- /dev/null +++ b/azure_jumpstart_ag/artifacts/PowerShell/SetupFabricWorkspace.ps1 @@ -0,0 +1,719 @@ +#################################################################################################### +# This PS script create all necessary Microsoft Fabric items to support Contoso Hypermarket +# data pipeline integration and dashboards + +# Access rights deploy Microsoft Fabric items used in Contoso Hypermarket scenario. +# Make sure Create Workspace is enabled in Frabric for service principals. +#Access settings using https://app.fabric.microsoft.com/admin-portal/tenantSettings?experience=power-bi +# +#################################################################################################### +$ProgressPreference = "SilentlyContinue" +Set-PSDebug -Strict + +$fabricConfigFile = (Get-Location).Path + "\fabric-config.json" + +##################################################################### +# Initialize the environment +##################################################################### +if ([System.IO.File]::Exists($fabricConfigFile)){ + $fabricConfig = Get-Content $fabricConfigFile | ConvertFrom-Json + $runAs = $fabricConfig.runAs + $tenantID = $fabricConfig.tenantID + $subscriptionID = $fabricConfig.subscriptionID + $templateBaseUrl = $fabricConfig.templateBaseUrl + $fabricWorkspaceName = $fabricConfig.fabricWorkspaceName + $fabricCapacityName = $fabricConfig.fabricCapacityName + $eventHubNamespace = $fabricConfig.eventHubNamespace + $eventHubName = $fabricConfig.eventHubName + $eventHubKeyName = $fabricConfig.eventHubKeyName + $eventHubPrimaryKey = $fabricConfig.eventHubPrimaryKey + $AgLogsDir = "." +} +else { + Write-Host "[$(Get-Date -Format t)] ERROR: Fabric configuration file '$fabricConfigFile' not found." -ForegroundColor DarkRed + Exit +} + +# Define variables to create Fabric workspace and KQL database +$fabricResource = "https://api.fabric.microsoft.com" # Fabric API resource to get access tokens for authorization to Fabric +$kustoResource = "https://api.kusto.windows.net" # Kusto API resource to get access tokens for authorization KQL database +$powerbiResource = "https://analysis.windows.net/powerbi/api" # Power BI API resource to get access token for authorization to Power BI +$script:apiUrl = "https://api.fabric.microsoft.com/v1" + +$global:workspaceId = "" +$global:kqlClusterUri = "" +$global:kqlDatabaseName = "" + +Start-Transcript -Path ($AgLogsDir + "\SetupFabricWorkspace.log") +Write-Host "[$(Get-Date -Format t)] INFO: Configuring Fabric Wrokspace" -ForegroundColor DarkGreen + +# Turn off subscription selection prompt in new AZ CLI +az config set core.login_experience_v2=off + +# Login to Azure as end user or managed identity to get access tokens for different API endpoints +if ($runAs -eq "user") { + # login using device code + az login --tenant $tenantID --use-device-code --allow-no-subscriptions +} +else { + # Login using managed identity + Write-Host "[$(Get-Date -Format t)] ERROR: Authentication type '$runAs' not supported to setup Microsoft Fabric workspace." -ForegroundColor DarkRed + Stop-Transcript + Exit +} + +# Set the Azure subscription +az account set --subscription $subscriptionID + +# Get access token to authorize access to Fabric APIs +$fabricAccessToken = (az account get-access-token --resource $fabricResource --query accessToken --output tsv) +if ($fabricAccessToken -eq '') { + write-host "ERROR: Failed to get access token using managed identity." + return +} + +function Set-Fabric-Workspace { + + # List Fabric capacities to assign to Fabric workspace to avoid Powrer BI Premium license + write-host "INFO: Checking if there is a Fabric capacity created with specified name." + $fabricCapacityApi = "https://api.fabric.microsoft.com/v1/capacities" + $headers = @{"Authorization" = "Bearer $fabricAccessToken";} + $httpResp = Invoke-WebRequest -Method Get -Uri $fabricCapacityApi -Headers $headers + if (!($httpResp.StatusCode -eq 200)){ + Write-Host "ERROR: Failed to get Fabric capacities." + return + } + + # Display current Fabric capacities + $fabricCapacities = (ConvertFrom-Json($httpResp.Content)).value + if ($fabricCapacities.Count -gt 0) + { + foreach ($fabricCapacity in $fabricCapacities){ + Write-Host "INFO: Fabric capacity name: $($fabricCapacity.displayName), id: $($fabricCapacity.Id), state: $($fabricCapacity.state)" + } + } + else { + Write-Host "ERROR: No Fabric capacities are available in your tenant to setup Fabric workspace. Create Fabric capacity or sign up for Trial license in your tenant to get started. Re-run this script when a new fabric capacity is created." + return + } + + # Verify if Fabric capactiy is configured + if (!$fabriccapacityName) { + Write-Host "[$(Get-Date -Format t)] ERROR: Fabric capacity is required to setup Fabric workspace. Choose one of the available fabric capacity name and update configuration file, and re-run this script." -ForegroundColor DarkRed + return + } + + # Verify if Fabric capacity exists with specific name + $fabricCapacity = $fabricCapacities | Where-Object { $_.displayName -eq $fabriccapacityName } + if (-not $fabricCapacity){ + Write-Host "ERROR: Fabric capacity not found with capacity name '$fabriccapacityName'" + return + } + else { + Write-Host "INFO: Found Fabric capacity with capacity name '$fabriccapacityName' and id '$($fabricCapacity.id)" + } + + # Assign fabric capacity id + $fabricCapacityId = $fabricCapacity.id + + # Create Fabric Workspace + $fabricWorkspacesApi = "https://api.fabric.microsoft.com/v1/workspaces" + $headers = @{"Authorization" = "Bearer $fabricAccessToken"; "Content-Type" = "application/json" } + + Write-Host "INFO: Creating Fabric workspace with name '$fabricWorkspaceName' and assigning Fabric Capacity id '$fabricCapacityId'" + + $apiPayload = "{'displayName': '$fabricWorkspaceName', 'capacityId': '$fabricCapacityId', 'Description': 'Contoso Hypermarket data analytics workspace.'}" + $workspaceResp = Invoke-WebRequest -Method Post -Uri $fabricWorkspacesApi -Body $apiPayload -Headers $headers + if (($workspaceResp.StatusCode -ge 200) -and ($workspaceResp.StatusCode -le 204)){ + Write-Host "INFO: Fabric workspace created with name '$fabricWorkspaceName' and assigned Fabric Capacity with id '$fabricCapacityId'" + } + else { + Write-Host "ERROR: Failed to create Fabric workspace." + return + } + + # Get newly created Fabric workspace id to create KQL database and other Fabric items + $fabricWorkspaceId = (ConvertFrom-Json($workspaceResp.Content)).id + Write-Host "INFO: Fabric workspace id is $fabricWorkspaceId" + + # Assign workspac variable to global variable + $global:workspaceId = $fabricWorkspaceId + + # Create Eventhouse to store retail data + $eventhouseApi = "https://api.fabric.microsoft.com/v1/workspaces/$fabricWorkspaceId/eventhouses" + $eventhouseName = "$fabriccapacityName-KQL".ToLower() + $apiPayload = "{'displayName': '$eventhouseName', 'description': 'Eventhouse to host KQL database for Contoso Hypermarket data.'}" + $headers = @{"Authorization" = "Bearer $fabricAccessToken"; "Content-Type" = "application/json" } + + Write-Host "INFO: Creating Eventhouse with name $eventhouseName." + $eventhouseResp = Invoke-WebRequest -Method Post -Uri $eventhouseApi -Body $apiPayload -Headers $headers + if (($eventhouseResp.StatusCode -ge 200) -and ($eventhouseResp.StatusCode -le 204)){ + Write-Host "INFO: Eventhouse created with name $eventhouseName." + } + else { + Write-Host "ERROR: Failed to create Eventhouse." + return + } + + # Get KQL database created in Eventhouse + Write-Host "INFO: Get default KQL database created in Eventhouse." + $kqlDatabasesApi = "https://api.fabric.microsoft.com/v1/workspaces/$fabricWorkspaceId/kqlDatabases" + $headers = @{"Authorization" = "Bearer $fabricAccessToken";} + $kqlDatabasesResp = Invoke-WebRequest -Method Get -Uri $kqlDatabasesApi -Headers $headers + $kqlDatabaseInfo = (ConvertFrom-Json($kqlDatabasesResp.Content)).value + $kqlQueryServiceUri = $kqlDatabaseInfo[0].properties.queryServiceUri + $kqlDatabaseId = $kqlDatabaseInfo[0].id + $kqlDatabaseName = $kqlDatabaseInfo[0].displayName + + $global:kqlClusterUri = $kqlQueryServiceUri + $global:kqlDatabaseName = $kqlDatabaseName + Write-Host "INFO: KQL database details. Database Name: $kqlDatabaseName, Database ID: $kqlDatabaseId, kqlQueryServiceUri: $kqlQueryServiceUri" + + # Download KQL script from GitHub + $kqlScriptUrl = $templateBaseUrl + "contoso_hypermarket/bicep/data/script.kql" + $kqlScript = (Invoke-WebRequest $kqlScriptUrl).Content + if (-not $kqlScript) { + write-host "ERROR: Failed to download KQL script to create database schema." + return + } + + # Get access token to authorize with the Kusto query endpoint + Write-Host "INFO: Get access token to authorize access to Kusto API endpoint $kustoResource" + $kustoAccessToken = (az account get-access-token --resource $kustoResource --query accessToken --output tsv) + if (-not $kustoAccessToken) { + write-host "ERROR: Failed to get access token to access Kusto endpoint $kustoResource." + return + } + + $headers = @{ + "Authorization" = "Bearer $kustoAccessToken" + "Content-Type" = "application/json" + } + + # Create payload to create KQL database schema and functions + Write-Host "INFO: Executing KQL script." + $body = @{ + db = $kqlDatabaseName + csl = "$kqlScript" + } | ConvertTo-Json + + $httpResp = Invoke-RestMethod -Method Post -Uri "$kqlQueryServiceUri/v1/rest/mgmt" -Headers $headers -Body $body + if ($httpResp.Tables.Count -ge 1){ + Write-Host "INFO: KQL script execution completed." + } + else { + Write-Host "ERROR: Failed to execute KQL script." + return + } + + # Download dashboard report and Update to use KQL database + $hyperMarketDashboardReport = $templateBaseUrl + "artifacts/fabric/ot_dashboard.json" + Write-Host "INFO: Downloading and preparing dashboard report to import into Fabric workspace." + $ordersDashboardBody = (Invoke-WebRequest -Method Get -Uri $hyperMarketDashboardReport).Content -replace '{{KQL_CLUSTER_URI}}', $kqlQueryServiceUri -replace '{{KQL_DATABASE_ID}}', $kqlDatabaseId -replace '{{FABRIC_WORKSPACE_ID}}', $fabricWorkspaceId + + # Convert the KQL dashboard report payload to base64 + Write-Host "INFO: Converting report content into base64 encoded format." + $base64Payload = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($ordersDashboardBody)) + + # Build KQL dashboard report payload from the report template + $body = @" +{ + "displayName": "Contoso_Hypermarket", + "description": "Contoso Hypermarket Dashboard Report", + "definition": { + "parts": [ + { + "path": "fabric-hypermarket-dashboard.json", + "payload": "$base64Payload", + "payloadType": "InlineBase64" + } + ] + } +} +"@ + + # Create KQL dashboard report + $kqlDashboardsApi = "https://api.fabric.microsoft.com/v1/workspaces/$fabricWorkspaceId/kqlDashboards" + $headers = @{"Authorization" = "Bearer $fabricAccessToken"; "Content-Type" = "application/json"} + $httpResp = Invoke-RestMethod -Method Post -Uri $kqlDashboardsApi -Headers $headers -Body $body + if ($httpResp.id.Length -gt 0){ + Write-Host "INFO: Created KQL dashboard report with ID: $($httpResp.id)" + } + else { + Write-Host "ERROR: Failed to create KQL dashboard report." + return + } + + # Get access token to authorize Power BI service. + Write-Host "INFO: Get access token to access Power BI APIs." + $powerbiAccessToken = (az account get-access-token --resource $powerbiResource --query accessToken --output tsv) + if ($powerbiAccessToken -eq '') { + Write-Host "ERROR: Failed to get access token to access Power BI service." + return + } + + # Power BI API endpoint to create EventHut connection + $powerBIEndpoint = "https://api.powerbi.com/v2.0/myorg/me/gatewayClusterCloudDatasource" + + # Create body to create EventHub data source + $eventHubEndpoint = "$eventHubNamespace.servicebus.windows.net" + $connectionBody = @" +{ + "datasourceName": "$fabricWorkspaceName-$eventHubName", + "datasourceType": "Extension", + "connectionDetails": "{\"endpoint\":\"$eventHubEndpoint\",\"entityPath\":\"$eventHubName\"}", + "singleSignOnType": "None", + "mashupTestConnectionDetails": { + "functionName": "EventHub.Contents", + "moduleName": "EventHub", + "moduleVersion": "1.0.8", + "parameters": [ + { + "name": "endpoint", + "type": "text", + "isRequired": true, + "value": "$eventHubEndpoint" + }, + { + "name": "entityPath", + "type": "text", + "isRequired": true, + "value": "$eventHubName" + } + ] + }, + "referenceDatasource": false, + "credentialDetails": { + "credentialType": "Basic", + "credentials": "{\"credentialData\":[{\"name\":\"username\",\"value\":\"$eventHubKeyName\"},{\"name\":\"password\",\"value\":\"$eventHubPrimaryKey\"}]}", + "encryptedConnection": "Any", + "privacyLevel": "Organizational", + "skipTestConnection": false, + "encryptionAlgorithm": "NONE", + "credentialSources": [] + }, + "allowDatasourceThroughGateway": true +} +"@ + + # Call API to create Event Hub connection in Power BI + Write-Host "INFO: Calling API to create EventHub data connection." + $dataConnectionResp = Invoke-RestMethod -Method Post -Uri $powerBIEndpoint -Body $connectionBody -ContentType "application/json" -Headers @{ Authorization = "Bearer $powerbiAccessToken" } + if ($dataConnectionResp.id.Length -gt 0){ + Write-Host "INFO: Created EventHub data connection with Connection ID: $($dataConnectionResp.id)" + } + else { + Write-Host "ERROR: Failed to create EventHub data connection." + return + } + + # Get connection id + $DataSourceConnectionId = $dataConnectionResp.id + Write-Host "INFO: EventHub DataSourceConnectionId: $DataSourceConnectionId" + + # Create header to authorize with Power BI service + $headers = @{ + "Authorization" = "Bearer $powerbiAccessToken" + "Content-Type" = "application/json" + } + + # Get MWC token to authorize and create data connections. This is a temporary workaround until Fabric releases API to create data connections + $mwcTokenBody = @" +{ + "type": "[Start] GetMWCTokenV2", + "workloadType": "Kusto", + "artifactObjectIds": [ + "$kqlDatabaseId" + ], + "workspaceObjectId": "$fabricWorkspaceId", + "capacityObjectId": "$fabricCapacityId" +} +"@ + + Write-Host "INFO: Requesting MWC token from Power BI API." + $mwcTokenApi = "https://wabi-us-central-b-primary-redirect.analysis.windows.net/metadata/v201606/generatemwctokenv2" + $mwcTokenResp = Invoke-RestMethod -Method Post -Uri $mwcTokenApi -Headers $headers -Body $mwcTokenBody + if ($mwcTokenResp.Token.Length -gt 0){ + Write-Host "INFO: Received MWC token." + } + else { + Write-Host "ERROR: Failed to get MWC token." + return + } + + $mwcToken = $mwcTokenResp.token + + # Event Hub connection body + $uriPrefix = $fabricCapacityId -replace '-', '' + $streamApi = "https://$uriPrefix.pbidedicated.windows.net/webapi/capacities/$fabricCapacityId/workloads/Kusto/KustoService/direct/v1/databases/$kqlDatabaseId/dataConnections/$DataSourceConnectionId" + $streamBody = @" +{ + "DataConnectionType": "EventHubDataConnection", + "DataConnectionProperties": { + "DatabaseArtifactId": "$kqlDatabaseId", + "TableName": "staging", + "MappingRuleName": "staging_mapping", + "EventSystemProperties": [], + "ConsumerGroup": "fabriccg", + "Compression": "None", + "DataFormat": "multijson", + "DataSourceConnectionId": "$DataSourceConnectionId", + "DataConnectionType": "EventHubDataConnection", + "DataConnectionName": "$fabricWorkspaceName" + } +} +"@ + + # Use MWC Token to create event data connection + Write-Host "INFO: Creating eventstream in KQL database to ingest data." + $dataSourceConnectionId = Invoke-RestMethod -Method Post -Uri $streamApi -Body $streamBody -ContentType "application/json" -Headers @{ Authorization = "MwcToken $mwcToken" } + if ($dataSourceConnectionId.dataSourceConnectionId){ + Write-Host "INFO: Created eventstream in KQL database with ID: $($dataSourceConnectionId.dataSourceConnectionId)" + } + else { + Write-Host "ERROR: Failed to create eventstream in KQL database. Review KQL database to make sure datastream is created." + } + + # Import data sceince notebook for sales forecast + # Download dashboard report and Update to use KQL database + $ordersSalesForecastNotebook = "orders_sales_forecast.ipynb" + Write-Host "INFO: Downloading and preparing nootebook to import into Fabric workspace." + $ordersNotebookBody = (Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/fabric/$ordersSalesForecastNotebook").Content -replace '{{KQL_CLUSTER_URI}}', $kqlQueryServiceUri -replace '{{KQL_DATABASE_NAME}}', $kqlDatabaseName + + # Convert the KQL dashboard report payload to base64 + Write-Host "INFO: Converting notebook content into base64 encoded format." + $base64Payload = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($ordersNotebookBody)) + + # Build KQL dashboard report payload from the report template + $body = @" +{ + "displayName": "Orders Sales Forecast Notebook", + "description": "A notebook description", + "definition": { + "format": "ipynb", + "parts": [ + { + "path": "$ordersSalesForecastNotebook", + "payload": "$base64Payload", + "payloadType": "InlineBase64" + } + ] + } +} +"@ + + # Create notebook in Fabric workspace + $nootebookApi = "https://api.fabric.microsoft.com/v1/workspaces/$fabricWorkspaceId/notebooks" + $headers = @{"Authorization" = "Bearer $fabricAccessToken"; "Content-Type" = "application/json"} + Invoke-RestMethod -Method Post -Uri $nootebookApi -Headers $headers -Body $body + Write-Host "INFO: Imported notebook in Fabric workspace." +} + +Function Invoke-FabricAPIRequest { + param( + [Parameter(Mandatory = $false)] [string] $authToken, + [Parameter(Mandatory = $true)] [string] $uri, + [Parameter(Mandatory = $false)] [ValidateSet('Get', 'Post', 'Delete', 'Put', 'Patch')] [string] $method = "Get", + [Parameter(Mandatory = $false)] $body, + [Parameter(Mandatory = $false)] [string] $contentType = "application/json; charset=utf-8", + [Parameter(Mandatory = $false)] [int] $timeoutSec = 240, + [Parameter(Mandatory = $false)] [int] $retryCount = 0 + ) + + $fabricHeaders = @{ + 'Content-Type' = $contentType + 'Authorization' = "Bearer {0}" -f $fabricAccessToken + } + + try { + + $requestUrl = "$($script:apiUrl)/$uri" + Write-Verbose "Calling $requestUrl" + + $response = Invoke-WebRequest -Headers $fabricHeaders -Method $method -Uri $requestUrl -Body $body -TimeoutSec $timeoutSec + $lroFailOrNoResultFlag = $false + if ($response.StatusCode -eq 202) { + do { + $asyncUrl = [string]$response.Headers.Location + Write-Host "Waiting for request to complete. Sleeping..." + + Start-Sleep -Seconds 5 + $response = Invoke-WebRequest -Headers $fabricHeaders -Method Get -Uri $asyncUrl + $lroStatusContent = $response.Content | ConvertFrom-Json + } + while ($lroStatusContent.status -ine "succeeded" -and $lroStatusContent.status -ine "failed") + + if ($lroStatusContent.status -ieq "succeeded") { + $resultUrl = [string]$response.Headers.Location + if ($resultUrl) { + $response = Invoke-WebRequest -Headers $fabricHeaders -Method Get -Uri $resultUrl + } + else { + $lroFailOrNoResultFlag = $true + } + } + else { + $lroFailOrNoResultFlag = $true + if ($lroStatusContent.error) { + throw "LRO API Error: '$($lroStatusContent.error.errorCode)' - $($lroStatusContent.error.message)" + } + } + } + + #if ($response.StatusCode -in @(200,201) -and $response.Content) + if (!$lroFailOrNoResultFlag -and $response.Content) { + $contentBytes = $response.RawContentStream.ToArray() + + # Test for BOM + if ($contentBytes[0] -eq 0xef -and $contentBytes[1] -eq 0xbb -and $contentBytes[2] -eq 0xbf) { + $contentText = [System.Text.Encoding]::UTF8.GetString($contentBytes[3..$contentBytes.Length]) + } + else { + $contentText = $response.Content + } + + $jsonResult = $contentText | ConvertFrom-Json + if ($jsonResult.value) { + $jsonResult = $jsonResult.value + } + + Write-Output $jsonResult -NoEnumerate + } + } + catch { + $response = $_.Exception.Response + } +} + + +Function Import-FabricItem { + param + ( + [Parameter(Mandatory)] + [string]$path, + + [Parameter(Mandatory)] + [string]$workspaceId, + + [hashtable]$itemProperties, + [switch]$skipIfExists + ) + + # Search for folders with .pbir and .pbism in it + $itemsInFolder = Get-ChildItem -LiteralPath $path | Where-Object { @(".pbism", ".pbir") -contains $_.Extension } + + if ($itemsInFolder.Count -eq 0) { + Write-Host "Cannot find valid item definitions (*.pbir; *.pbism) in the '$path'" + return + } + + if ($itemsInFolder | Where-Object { $_.Extension -ieq ".pbir" }) { + $itemType = "Report" + } + elseif ($itemsInFolder | Where-Object { $_.Extension -ieq ".pbism" }) { + $itemType = "SemanticModel" + } + else { + throw "Cannot determine the itemType." + } + + # Get existing items of the workspace + $items = Invoke-FabricAPIRequest -Uri "workspaces/$workspaceId/items" -Method Get + + Write-Host "Existing items in the workspace: $($items.Count)" + $files = Get-ChildItem -LiteralPath $path -Recurse -Attributes !Directory + + # Remove files not required for the API: item.*.json; cache.abf; .pbi folder + $files = $files | Where-Object { $_.Name -notlike "item.*.json" -and $_.Name -notlike "*.abf" -and $_.Directory.Name -notlike ".pbi" } + + # Prioritizes reading the displayName and type from itemProperties parameter + $displayName = $null + if ($null -ne $itemProperties) { + $displayName = $itemProperties.displayName + } + + # Try to read the item properties from the .platform file if not found in itemProperties + if ((!$itemType -or !$displayName) -and (Test-Path -LiteralPath "$path\.platform")) { + $itemMetadataStr = Get-Content -LiteralPath "$path\.platform" + + $itemMetadata = $itemMetadataStr | ConvertFrom-Json + $itemType = $itemMetadata.metadata.type + $displayName = $itemMetadata.metadata.displayName + } + + if (!$itemType -or !$displayName) { + throw "Cannot import item if any of the following properties is missing: itemType, displayName" + } + + $itemPathAbs = Resolve-Path -LiteralPath $path + $parts = $files |ForEach-Object { + $filePath = $_.FullName + if ($filePath -like "*.pbir") { + $fileContentText = Get-Content -LiteralPath $filePath + $pbirJson = $fileContentText | ConvertFrom-Json + + $datasetId = $itemProperties.semanticModelId + if ($datasetId -or ($pbirJson.datasetReference.byPath -and $pbirJson.datasetReference.byPath.path)) { + if (!$datasetId) { + throw "Cannot import directly a report using byPath connection. You must first resolve the semantic model id and pass it through the 'itemProperties.semanticModelId' parameter." + } + else { + Write-Host "Binding to semantic model: $datasetId" + } + + $pbirJson.datasetReference.byPath = $null + $pbirJson.datasetReference.byConnection = @{ + "connectionString" = $null + "pbiServiceModelId" = $null + "pbiModelVirtualServerName" = "sobe_wowvirtualserver" + "pbiModelDatabaseName" = "$datasetId" + "name" = "EntityDataSource" + "connectionType" = "pbiServiceXmlaStyleLive" + } + + $newPBIR = $pbirJson | ConvertTo-Json + $fileContent = [system.Text.Encoding]::UTF8.GetBytes($newPBIR) + } + # if its byConnection then just send original + else { + $fileContent = [system.Text.Encoding]::UTF8.GetBytes($fileContentText) + } + } + else { + $fileContent = [System.IO.File]::ReadAllBytes($filePath) + } + + $partPath = $filePath.Replace($itemPathAbs, "").TrimStart("\").Replace("\", "/") + if ($fileContent) { + $fileEncodedContent = [Convert]::ToBase64String($fileContent) + } else { + $fileEncodedContent = "" + } + + Write-Output @{ + Path = $partPath + Payload = $fileEncodedContent + PayloadType = "InlineBase64" + } + } + + Write-Host "Payload parts:" + + $parts | ForEach-Object { Write-Host "part: $($_.Path)" } + $itemId = $null + + # Check if there is already an item with same displayName and type + $foundItem = $items | Where-Object { $_.type -ieq $itemType -and $_.displayName -ieq $displayName } + if ($foundItem) { + if ($foundItem.Count -gt 1) { + throw "Found more than one item for displayName '$displayName'" + } + + Write-Host "Item '$displayName' of type '$itemType' already exists." -ForegroundColor Yellow + $itemId = $foundItem.id + } + + if ($null -eq $itemId ) { + write-host "Creating a new item" + # Prepare the request + $itemRequest = @{ + displayName = $displayName + type = $itemType + definition = @{ + Parts = $parts + } + } | ConvertTo-Json -Depth 3 + + $createItemResult = Invoke-FabricAPIRequest -uri "workspaces/$workspaceId/items" -method Post -body $itemRequest + $itemId = $createItemResult.id + + write-host "Created a new item with ID '$itemId' $([datetime]::Now.ToString("s"))" -ForegroundColor Green + Write-Output @{ + "id" = $itemId + "displayName" = $displayName + "type" = $itemType + } + } + else { + if ($skipIfExists) { + write-host "Item '$displayName' of type '$itemType' already exists. Skipping." -ForegroundColor Yellow + } + else { + write-host "Updating item definition" + $itemRequest = @{ + definition = @{ + Parts = $parts + } + } | ConvertTo-Json -Depth 3 + + Invoke-FabricAPIRequest -Uri "workspaces/$workspaceId/items/$itemId/updateDefinition" -Method Post -Body $itemRequest + write-host "Updated item with ID '$itemId' $([datetime]::Now.ToString("s"))" -ForegroundColor Green + } + + Write-Output @{ + "id" = $itemId + "displayName" = $displayName + "type" = $itemType + } + } +} + +# Function to import Power BI reports into Fabric workspace +function Set-PowerBI-Project { + # Parameters + $pbipFolder = Get-Location # Path to the folder containing Power BI project files, default to current directory + + # Download PowerBI report zip file + $pbipFileName = "Contoso_Hypermarket.zip" + $localFilePath = "$pbipFolder\$pbipFileName" + Write-Host "INFO: Downloading Power BI report zip file." + Invoke-WebRequest "https://aka.ms/JSContosoHypermarketReportFiles" -OutFile $localFilePath + + Write-Host "INFO: Unzipping Power BI report zip file." + Expand-Archive -Path $localFilePath -DestinationPath $pbipFolder -Force + + $pbipSemanticModelPath = "$pbipFolder\Contoso_Hypermarket.SemanticModel" + $pbipReportPath = "$pbipFolder\Contoso_Hypermarket.Report" + + # Update KQL endpoint + $modelFilePath = "$pbipSemanticModelPath\model.bim" + + # Replace KQL cluster URI for the model to connect + Write-Host "INFO: Replace KQL cluster URI in the semantic model." + (Get-Content -Path $modelFilePath) -replace '{{FABRIC_KQL_CLUSTER_URI}}', $global:kqlClusterUri -replace '{{FABRIC_KQL_DATABASE}}', $global:kqlDatabaseName| Set-Content -Path $modelFilePath + + # Import the semantic model and save the item id + Write-Host "INFO: Import the semantic model and save the item id." + $semanticModelImport = Import-FabricItem -workspaceId $global:workspaceId -path $pbipSemanticModelPath + Write-Host "INFO: Imported semantic model with the item id $($semanticModelImport.id)" + + # Import the report and ensure its binded to the previous imported report + Write-Host "INFO: Import the PowerBI report and save the item id." + $reportImport = Import-FabricItem -workspaceId $global:workspaceId -path $pbipReportPath -itemProperties @{"semanticModelId" = $semanticModelImport.Id} + Write-Host "INFO: Imported PowerBI report with the item id $($reportImport.id)" + + # Refresh semantic model + $datasetUri = "https://api.powerbi.com/v1.0/myorg/groups/$($global:workspaceId)/datasets/$($semanticModelImport.Id)/refreshes" + $headers = @{"Authorization" = "Bearer $fabricAccessToken";} + + $datsetResp = Invoke-WebRequest -Method Post -Uri $datasetUri -Headers $headers + if (($datsetResp.StatusCode -ge 200) -and ($datsetResp.StatusCode -le 204)){ + Write-Host "INFO: Semantic model refreshed successfully." + } + else { + Write-Host "ERROR: Semantic model refresh failed. Refresh semantic model manually in Microsoft Fabric workspace." + } + + # Print Fabric workspace URL + $workspaceUrl = "https://app.fabric.microsoft.com/groups/$($global:workspaceId)/" + Write-Host "INFO: Microsoft Fabric workspace URL: $workspaceUrl" +} + +# Create Fabric workspace and KQL database +Set-Fabric-Workspace + +# Import PowerBI report +Set-PowerBI-Project + +# Stop logging into the log file +Stop-Transcript diff --git a/azure_jumpstart_ag/artifacts/PowerShell/Winget.ps1 b/azure_jumpstart_ag/artifacts/PowerShell/Winget.ps1 new file mode 100644 index 0000000000..c2debe62ae --- /dev/null +++ b/azure_jumpstart_ag/artifacts/PowerShell/Winget.ps1 @@ -0,0 +1,100 @@ +$ErrorActionPreference = 'SilentlyContinue' + +$AgDir = 'C:\Ag' +$AgLogsDir = "$AgDir\Logs" +$AgConfig = Import-PowerShellDataFile -Path $Env:AgConfigPath + +$logFilePath = Join-Path -Path $AgLogsDir -ChildPath ('WinGet-provisioning-' + (Get-Date -Format 'yyyyMMddHHmmss') + '.log') + +Start-Transcript -Path $logFilePath -Force -ErrorAction SilentlyContinue + +# Install WinGet PowerShell modules +Install-PSResource -Name Microsoft.WinGet.Client -Scope AllUsers -Quiet -AcceptLicense -TrustRepository + +# Install WinGet CLI +$null = Repair-WinGetPackageManager -AllUsers -Force -Latest + +Write-Header 'Installing WinGet packages and DSC configurations' +$winget = Join-Path -Path $env:LOCALAPPDATA -ChildPath Microsoft\WindowsApps\winget.exe + +# Windows Terminal needs to be installed per user, while WinGet Configuration runs as SYSTEM. Hence, this package is installed in the logon script. +& $winget install Microsoft.WindowsTerminal --version 1.18.3181.0 -s winget --silent --accept-package-agreements + +############################################################## +# Install Winget packages +############################################################## +$maxRetries = 3 +$retryDelay = 30 # seconds + +$retryCount = 0 +$success = $false + +while (-not $success -and $retryCount -lt $maxRetries) { + Write-Host "Winget packages specified" + + try { + foreach ($app in $AgConfig.WingetPackagesList) { + Write-Host "Installing $app" + & $winget install -e --id $app --silent --accept-package-agreements --accept-source-agreements --ignore-warnings + } + + # If the command succeeds, set $success to $true to exit the loop + $success = $true + } + catch { + # If an exception occurs, increment the retry count + $retryCount++ + + # If the maximum number of retries is not reached yet, display an error message + if ($retryCount -lt $maxRetries) { + Write-Host "Attempt $retryCount failed. Retrying in $retryDelay seconds..." + Start-Sleep -Seconds $retryDelay + } + else { + Write-Host "All attempts failed. Exiting..." + exit 1 # Stop script execution if maximum retries reached + } + } +} + +# Create Desktop shortcuts + +# Creating Microsoft SQL Server Management Studio (SSMS) desktop shortcut +Write-Host "`n" +Write-Host "Creating Microsoft SQL Server Management Studio (SSMS) desktop shortcut" +Write-Host "`n" +$TargetFile = "C:\Program Files (x86)\Microsoft SQL Server Management Studio 20\Common7\IDE\ssms.exe" +$ShortcutFile = "C:\Users\$Env:adminUsername\Desktop\Microsoft SQL Server Management Studio.lnk" +$WScriptShell = New-Object -ComObject WScript.Shell +$Shortcut = $WScriptShell.CreateShortcut($ShortcutFile) +$Shortcut.TargetPath = $TargetFile +$Shortcut.Save() + +# Create Azure Data Studio desktop shortcut +Write-Header "Creating Azure Data Studio Desktop Shortcut" +Write-Host "`n" +$TargetFile = "C:\Users\$Env:adminUsername\AppData\Local\Programs\Azure Data Studio\azuredatastudio.exe" +$ShortcutFile = "C:\Users\$Env:adminUsername\Desktop\Azure Data Studio.lnk" +$WScriptShell = New-Object -ComObject WScript.Shell +$Shortcut = $WScriptShell.CreateShortcut($ShortcutFile) +$Shortcut.TargetPath = $TargetFile +$Shortcut.Save() + +# Create VSCode desktop shortcut +Write-Header "Creating Visual Studio Code Desktop Shortcut" +Write-Host "`n" +$TargetFile = "C:\Users\$Env:adminUsername\AppData\Local\Programs\Microsoft VS Code\Code.exe" +$ShortcutFile = "C:\Users\$Env:adminUsername\Desktop\VSCode.lnk" +$WScriptShell = New-Object -ComObject WScript.Shell +$Shortcut = $WScriptShell.CreateShortcut($ShortcutFile) +$Shortcut.TargetPath = $TargetFile +$Shortcut.Save() + +# Start remaining logon scripts +Get-ScheduledTask *LogonScript* | Start-ScheduledTask + +#Cleanup +Unregister-ScheduledTask -TaskName 'WinGetLogonScript' -Confirm:$false +Unregister-ScheduledTask -TaskName "Restart-Computer-Delayed" -Confirm:$false + +Stop-Transcript \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/PowerShell/tests/Invoke-Test.ps1 b/azure_jumpstart_ag/artifacts/PowerShell/tests/Invoke-Test.ps1 new file mode 100644 index 0000000000..3e39ddec30 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/PowerShell/tests/Invoke-Test.ps1 @@ -0,0 +1,56 @@ +#Requires -Modules @{ ModuleName="Pester"; ModuleVersion="5.6.0"} + +$AgConfig = Import-PowerShellDataFile -Path $Env:AgConfigPath +$AgTestsDir = $AgConfig.AgDirectories["AgTestsDir"] +Invoke-Pester -Path "$AgTestsDir\common.tests.ps1" -Output Detailed -PassThru -OutVariable tests_common +$tests_passed = $tests_common.Passed.Count +$tests_failed = $tests_common.Failed.Count + +Invoke-Pester -Path "$AgTestsDir\k8s.tests.ps1" -Output Detailed -PassThru -OutVariable tests_k8s +$tests_passed = $tests_passed + $tests_k8s.Passed.Count +$tests_failed = $tests_failed + $tests_k8s.Failed.Count + +Write-Output "Tests succeeded: $tests_passed" +Write-Output "Tests failed: $tests_failed" + +Write-Header "Adding deployment test results to wallpaper using BGInfo" + +Set-Content "$Env:windir\TEMP\agora-tests-succeeded.txt" $tests_passed +Set-Content "$Env:windir\TEMP\agora-tests-failed.txt" $tests_failed + +bginfo.exe $AgTestsDir\ag-bginfo.bgi /timer:0 /NOLICPROMPT + + +$DeploymentStatusPath = "C:\Ag\Logs\DeploymentStatus.log" + +Write-Header "Exporting deployment test results to $DeploymentStatusPath" + +Write-Output "Deployment Status" | Out-File -FilePath $DeploymentStatusPath + +Write-Output "`nTests succeeded: $tests_passed" | Out-File -FilePath $DeploymentStatusPath -Append +Write-Output "Tests failed: $tests_failed`n" | Out-File -FilePath $DeploymentStatusPath -Append + +Write-Output "To get an updated deployment status, open Windows Terminal and run:" | Out-File -FilePath $DeploymentStatusPath -Append +Write-Output "C:\Ag\Tests\Invoke-Test.ps1`n" | Out-File -FilePath $DeploymentStatusPath -Append + +Write-Output "Failed:" | Out-File -FilePath $DeploymentStatusPath -Append +$tests_common.Failed | Out-File -FilePath $DeploymentStatusPath -Append +$tests_k8s.Failed | Out-File -FilePath $DeploymentStatusPath -Append + +Write-Output "Passed:" | Out-File -FilePath $DeploymentStatusPath -Append +$tests_k8s.Passed | Out-File -FilePath $DeploymentStatusPath -Append +$tests_common.Passed | Out-File -FilePath $DeploymentStatusPath -Append + +Write-Header "Exporting deployment test results to resource group tag DeploymentStatus" + +$DeploymentStatusString = "Tests succeeded: $tests_passed Tests failed: $tests_failed" + +$tags = Get-AzResourceGroup -Name $env:resourceGroup | Select-Object -ExpandProperty Tags + +if ($null -ne $tags) { + $tags["DeploymentStatus"] = $DeploymentStatusString +} else { + $tags = @{"DeploymentStatus" = $DeploymentStatusString} +} + +$null = Set-AzResourceGroup -ResourceGroupName $env:resourceGroup -Tag $tags \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/PowerShell/tests/ag-bginfo.bgi b/azure_jumpstart_ag/artifacts/PowerShell/tests/ag-bginfo.bgi new file mode 100644 index 0000000000..7c6526cbd1 Binary files /dev/null and b/azure_jumpstart_ag/artifacts/PowerShell/tests/ag-bginfo.bgi differ diff --git a/azure_jumpstart_ag/artifacts/PowerShell/tests/common.tests.ps1 b/azure_jumpstart_ag/artifacts/PowerShell/tests/common.tests.ps1 new file mode 100644 index 0000000000..eff98e3869 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/PowerShell/tests/common.tests.ps1 @@ -0,0 +1,15 @@ +BeforeDiscovery { + + # Login to Azure PowerShell with Managed Identity + Connect-AzAccount -Identity -Subscription $env:subscriptionId + +} +Describe "ArcBox resource group" { + BeforeAll { + $ResourceGroupName = $env:resourceGroup + } + It "should have 79 resources or more" { + (Get-AzResource -ResourceGroupName $ResourceGroupName).count | Should -BeGreaterOrEqual 79 + } +} + diff --git a/azure_jumpstart_ag/artifacts/PowerShell/tests/k8s.tests.ps1 b/azure_jumpstart_ag/artifacts/PowerShell/tests/k8s.tests.ps1 new file mode 100644 index 0000000000..edd123e874 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/PowerShell/tests/k8s.tests.ps1 @@ -0,0 +1,66 @@ +BeforeDiscovery { + + # Login to Azure PowerShell with Managed Identity + Connect-AzAccount -Identity -Subscription $env:subscriptionId + + # Import the configuration data + $AgConfig = Import-PowerShellDataFile -Path $Env:AgConfigPath + + # Initialize an array to hold the ArcClusterName values + $ArcClusterNames = @() + + # Loop through each SiteConfig and extract the ArcClusterName + foreach ($site in $AgConfig.SiteConfig.Values) { + $ArcClusterNames += $site.ArcClusterName + } + +} + +Describe "" -ForEach $ArcClusterNames { + BeforeAll { + $cluster = $_ + "-$($Env:namingGuid)" + $cluster + $connectedCluster = Get-AzConnectedKubernetes -ResourceGroupName $env:resourceGroup -SubscriptionId $env:subscriptionId -Name $cluster + $aioStatus = az iot ops check --as-object 2>$null | ConvertFrom-Json + $aioPodStatus = kubectl get pods -n azure-iot-operations -o json | ConvertFrom-Json | Where-Object {$PSItem.items.metadata.name -notlike "*fluent-bit*"} + $aioPodStatusItems = $aioPodStatus.items | Where-Object { + $_.spec.containers.name -notmatch "fluent-bit" + } + # Run kubectl to get service details in the azure-iot-operations namespace + $aioServices = kubectl get svc -n azure-iot-operations -o json | ConvertFrom-Json + } + It "Cluster exists" { + $connectedCluster | Should -Not -BeNullOrEmpty + } + It "Azure Arc Connected cluster is connected" { + $connectedCluster.ConnectivityStatus | Should -Be "Connected" + } + It "All pods should be in Running, Completed, or have no containers in CrashLoopBackOff" { + foreach ($pod in $aioPodStatusItems) { + # Check the overall pod phase first + if ($pod.status.phase -in @("Running", "Succeeded")) { + # Now check container statuses within each pod + $containersInCrashLoop = $pod.status.containerStatuses | Where-Object { + $_.state.waiting.reason -eq "CrashLoopBackOff" + } + + # Ensure there are no containers in CrashLoopBackOff for this pod + $containersInCrashLoop | Should -BeNullOrEmpty -Because "Pod $($pod.metadata.name) should not have containers in CrashLoopBackOff" + } + else { + # If the pod phase is not Running or Succeeded, fail the test + $pod.status.phase | Should -BeIn @("Running", "Succeeded") -Because "Pod $($pod.metadata.name) should be Running or Completed" + } + } + } + It "Azure IoT Operations - aio-operator service should be online with a valid ClusterIP" { + # Find the aio-operator service in the list + $aioOperatorService = $aioServices.items | Where-Object { $_.metadata.name -eq "aio-operator" } + + # Verify that the aio-operator service exists + $aioOperatorService | Should -Not -BeNullOrEmpty -Because "The aio-operator service should exist in the azure-iot-operations namespace" + + # Verify that the aio-operator service has a ClusterIP assigned + $aioOperatorService.spec.clusterIP | Should -Not -BeNullOrEmpty -Because "The aio-operator service should have a valid ClusterIP assigned" + } +} diff --git a/azure_jumpstart_ag/artifacts/fabric/orders_sales_forecast.ipynb b/azure_jumpstart_ag/artifacts/fabric/orders_sales_forecast.ipynb new file mode 100644 index 0000000000..cb0163e5c0 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/fabric/orders_sales_forecast.ipynb @@ -0,0 +1 @@ +{"cells":[{"cell_type":"markdown","source":["\n","#### Run the cell below to install the required packages for Copilot\n"],"metadata":{"jupyter":{"magics_cell_name":"magics-cell-markdown","magics_signature":"27ac753c3c60167f65c4d05fa7809cd85f1f0273d5b842aca4f65a01"},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"7a59fda1-4e93-45fb-8d19-7db1a882cc5e"},{"cell_type":"code","source":["# Run this cell to install the required packages for Copilot\n","%load_ext dscopilot_installer\n","%activate_dscopilot"],"outputs":[],"execution_count":null,"metadata":{"jupyter":{"magics_cell_name":"magics-cell-code","magics_signature":"6565d62221c469ab3707694ccbef2e4568d575dc1ba3ebac23f0f052","magics_version":"1.0"},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"201b7702-02d9-4d89-abc7-0cdbf6277f24"},{"cell_type":"markdown","source":["# Contoso Hypermarket Orders sales forecast ML notebook"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"ef02f63e-941b-42c0-8481-ce8aac727fa8"},{"cell_type":"markdown","source":["## Case 1: Forecast sales across products for a particular store location."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"75fcef09-e93e-421d-a93a-84aa5fac24ef"},{"cell_type":"markdown","source":["#### Set up MLflow experiment tracking"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"b1418874-4b23-4dae-8748-07e756bf70f4"},{"cell_type":"code","source":["# Set up MLflow for experiment tracking\n","import mlflow\n","\n","IS_SAMPLE = False # if TRUE, use only rows of data for training, otherwise use all data\n","SAMPLE_ROWS = 5000 # if IS_SAMPLE is True, use only this number of rows for training\n","EXPERIMENT_NAME = \"orders-sales-forecast\" # MLflow experiment name\n","\n","mlflow.set_experiment(EXPERIMENT_NAME)\n","mlflow.autolog(disable=True) # Disable MLflow autologging"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":3,"statement_ids":[3],"state":"finished","livy_statement_state":"available","session_id":"3945a8d4-06c7-4a20-bac5-81538ccc6266","normalized_state":"finished","queued_time":"2024-11-04T20:08:34.5715751Z","session_start_time":null,"execution_start_time":"2024-11-04T20:08:35.2969409Z","execution_finish_time":"2024-11-04T20:08:39.4325786Z","parent_msg_id":"e0263fb0-aea8-4e02-896f-df63ace091c0"},"text/plain":"StatementMeta(, 3945a8d4-06c7-4a20-bac5-81538ccc6266, 3, Finished, Available, Finished)"},"metadata":{}}],"execution_count":2,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"edac2e41-e4ec-4a84-adad-d57938e17562"},{"cell_type":"markdown","source":["### Step 1: Ingest data\n","#### Load orders data from KQL database to prepare for ML modeling\n","\n","> [!IMPORTANT]\n","> Make sure you have enough data generated using data emulator."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"9fa68416-1c4d-4481-8ec2-c2571310afbf"},{"cell_type":"code","source":["# Read from Kusto\n","# kustoQuery = \"['orders'] | mv-expand li = parse_json(line_items) | project order_date, store_id, order_id, product_id = toint(li.product_id), quantity = toint(li.quantity), price = toreal(li.price), item_total = toreal(li.item_total), order_total\"\n","ordersQuery = \"['orders'] | mv-expand li = parse_json(line_items) | project order_date, store_id, order_id, product_id = toint(li.product_id), quantity = toint(li.quantity), price = toreal(li.price), item_total = toreal(li.item_total), order_total\"\n","inventoryQuery = \"['inventory'] | project date_time, store_id, product_id, in_stock, retail_price\"\n","productsQuery = \"['products'] | project product_id, name, category, photo_path, price_range, stock\"\n","# The query URI for reading the data e.g. https://<>.kusto.data.microsoft.com.\n","kustoUri = \"{{KQL_CLUSTER_URI}}\"\n","# The database with data to be read.\n","database = \"{{KQL_DATABASE_NAME}}\"\n","# The access credentials.\n","accessToken = mssparkutils.credentials.getToken(kustoUri)\n","ordersDf = spark.read\\\n"," .format(\"com.microsoft.kusto.spark.synapse.datasource\")\\\n"," .option(\"accessToken\", accessToken)\\\n"," .option(\"kustoCluster\", kustoUri)\\\n"," .option(\"kustoDatabase\", database)\\\n"," .option(\"kustoQuery\", ordersQuery).load()\n","inventoryDf = spark.read\\\n"," .format(\"com.microsoft.kusto.spark.synapse.datasource\")\\\n"," .option(\"accessToken\", accessToken)\\\n"," .option(\"kustoCluster\", kustoUri)\\\n"," .option(\"kustoDatabase\", database)\\\n"," .option(\"kustoQuery\", inventoryQuery).load()\n","productsDf = spark.read\\\n"," .format(\"com.microsoft.kusto.spark.synapse.datasource\")\\\n"," .option(\"accessToken\", accessToken)\\\n"," .option(\"kustoCluster\", kustoUri)\\\n"," .option(\"kustoDatabase\", database)\\\n"," .option(\"kustoQuery\", productsQuery).load()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":5,"statement_ids":[5],"state":"finished","livy_statement_state":"available","session_id":"1aeb6edd-3450-4a72-a646-81cab3450974","normalized_state":"finished","queued_time":"2024-11-04T15:57:52.7175715Z","session_start_time":null,"execution_start_time":"2024-11-04T15:57:53.1854873Z","execution_finish_time":"2024-11-04T15:58:02.3738514Z","parent_msg_id":"01b395a9-39ce-49ef-bd5b-1d25ca30965d"},"text/plain":"StatementMeta(, 1aeb6edd-3450-4a72-a646-81cab3450974, 5, Finished, Available, Finished)"},"metadata":{}}],"execution_count":2,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"},"jupyter":{"source_hidden":false}},"id":"941a85a3-eaf6-4f2d-b862-2822a11cba86"},{"cell_type":"markdown","source":["#### Verifying token availability"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e877707b-df48-40ca-9f95-27615082c0de"},{"cell_type":"code","source":["import requests\n","\n","# Define a simple test query\n","test_query = \"['inventory'] | take 1\"\n","\n","# Define the request headers with the access token\n","headers = {\n"," \"Authorization\": f\"Bearer {accessToken}\",\n"," \"Content-Type\": \"application/json\"\n","}\n","\n","# Define the request payload\n","payload = {\n"," \"db\": database,\n"," \"csl\": test_query\n","}\n","\n","# Make the request to the Kusto cluster\n","response = requests.post(f\"{kustoUri}/v1/rest/query\", headers=headers, json=payload)\n","\n","# Check if the request was successful\n","if response.status_code == 200:\n"," print(\"Access token is valid and has the necessary permissions.\")\n","else:\n"," print(f\"Failed to validate access token. Status code: {response.status_code}, Response: {response.text}\")"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":6,"statement_ids":[6],"state":"finished","livy_statement_state":"available","session_id":"1aeb6edd-3450-4a72-a646-81cab3450974","normalized_state":"finished","queued_time":"2024-11-04T15:58:09.2861621Z","session_start_time":null,"execution_start_time":"2024-11-04T15:58:09.6630073Z","execution_finish_time":"2024-11-04T15:58:10.7161928Z","parent_msg_id":"00ba4704-6677-43f0-81df-205cd8d56524"},"text/plain":"StatementMeta(, 1aeb6edd-3450-4a72-a646-81cab3450974, 6, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["Access token is valid and has the necessary permissions.\n"]}],"execution_count":3,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"dca0ec6b-628f-4e91-9c60-5d7b1e78e0ed"},{"cell_type":"markdown","source":["### Step 2: Perform Exploratory Data Analysis"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"d3363923-eb3e-4c3a-928e-3f304fc85fd0"},{"cell_type":"markdown","source":["#### Import libraries\n","\n","Before any analysis, you need to import the required libraries."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"0b764c51-1738-49a5-a8cf-e340518e9d8a"},{"cell_type":"code","source":["# Importing required libraries\n","import warnings\n","import itertools\n","import numpy as np\n","import matplotlib.pyplot as plt\n","warnings.filterwarnings(\"ignore\")\n","plt.style.use('fivethirtyeight')\n","import pandas as pd\n","import statsmodels.api as sm\n","import matplotlib\n","matplotlib.rcParams['axes.labelsize'] = 14\n","matplotlib.rcParams['xtick.labelsize'] = 12\n","matplotlib.rcParams['ytick.labelsize'] = 12\n","matplotlib.rcParams['text.color'] = 'k'\n","from sklearn.metrics import mean_squared_error,mean_absolute_percentage_error"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":7,"statement_ids":[7],"state":"finished","livy_statement_state":"available","session_id":"1aeb6edd-3450-4a72-a646-81cab3450974","normalized_state":"finished","queued_time":"2024-11-04T15:59:02.4045828Z","session_start_time":null,"execution_start_time":"2024-11-04T15:59:02.8317392Z","execution_finish_time":"2024-11-04T15:59:10.0846956Z","parent_msg_id":"2207d7d8-0dfb-47d7-a8c8-f514e39ba2d2"},"text/plain":"StatementMeta(, 1aeb6edd-3450-4a72-a646-81cab3450974, 7, Finished, Available, Finished)"},"metadata":{}}],"execution_count":4,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"eece5426-68f6-4a0b-a478-2d4381322ac3"},{"cell_type":"markdown","source":["#### Display raw data"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e48037a1-e1cb-4d33-9aa5-57faea8be1a2"},{"cell_type":"code","source":["# Display data in dataframes.\n","ordersDf.show()\n","productsDf.show()\n","inventoryDf.show()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":8,"statement_ids":[8],"state":"finished","livy_statement_state":"available","session_id":"1aeb6edd-3450-4a72-a646-81cab3450974","normalized_state":"finished","queued_time":"2024-11-04T15:59:16.8616111Z","session_start_time":null,"execution_start_time":"2024-11-04T15:59:17.2765554Z","execution_finish_time":"2024-11-04T15:59:58.8909583Z","parent_msg_id":"7c7b2b1b-596d-4377-bbd3-25919e0d1097"},"text/plain":"StatementMeta(, 1aeb6edd-3450-4a72-a646-81cab3450974, 8, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["+--------------------+--------+------------------+----------+--------+-----+------------------+------------------+\n| order_date|store_id| order_id|product_id|quantity|price| item_total| order_total|\n+--------------------+--------+------------------+----------+--------+-----+------------------+------------------+\n|2024-09-26 13:25:...| NYC|20240926132502-003| 12| 8| 3.0| 24.0| 60.95|\n|2024-09-26 13:25:...| NYC|20240926132502-003| 4| 10| 3.0| 30.0| 60.95|\n|2024-09-26 13:25:...| NYC|20240926132502-003| 9| 10| 0.2| 2.0| 60.95|\n|2024-09-26 13:25:...| NYC|20240926132502-003| 2| 3| 0.15| 0.45| 60.95|\n|2024-09-26 13:25:...| NYC|20240926132502-003| 8| 8| 0.5| 4.0| 60.95|\n|2024-09-26 13:25:...| NYC|20240926132502-003| 7| 2| 0.25| 0.5| 60.95|\n|2024-09-26 13:25:...| SEA|20240926132502-004| 9| 9| 0.2| 1.8| 32.2|\n|2024-09-26 13:25:...| SEA|20240926132502-004| 10| 3| 0.3|0.8999999999999999| 32.2|\n|2024-09-26 13:25:...| SEA|20240926132502-004| 12| 2| 3.0| 6.0| 32.2|\n|2024-09-26 13:25:...| SEA|20240926132502-004| 8| 7| 0.5| 3.5| 32.2|\n|2024-09-26 13:25:...| SEA|20240926132502-004| 5| 8| 2.5| 20.0| 32.2|\n|2024-09-26 13:25:...| SEA|20240926132502-005| 9| 9| 0.2| 1.8|51.099999999999994|\n|2024-09-26 13:25:...| SEA|20240926132502-005| 3| 8| 0.7| 5.6|51.099999999999994|\n|2024-09-26 13:25:...| SEA|20240926132502-005| 11| 4| 2.0| 8.0|51.099999999999994|\n|2024-09-26 13:25:...| SEA|20240926132502-005| 5| 9| 2.5| 22.5|51.099999999999994|\n|2024-09-26 13:25:...| SEA|20240926132502-005| 4| 2| 3.0| 6.0|51.099999999999994|\n|2024-09-26 13:25:...| SEA|20240926132502-005| 2| 6| 0.15|0.8999999999999999|51.099999999999994|\n|2024-09-26 13:25:...| SEA|20240926132502-005| 8| 9| 0.5| 4.5|51.099999999999994|\n|2024-09-26 13:25:...| SEA|20240926132502-005| 10| 6| 0.3|1.7999999999999998|51.099999999999994|\n|2024-09-26 13:25:...| CHI|20240926132502-006| 11| 5| 2.0| 10.0| 65.0|\n+--------------------+--------+------------------+----------+--------+-----+------------------+------------------+\nonly showing top 20 rows\n\n+----------+------------+----------+--------------------+--------------------+-----+\n|product_id| name| category| photo_path| price_range|stock|\n+----------+------------+----------+--------------------+--------------------+-----+\n| 1| Red Apple| Fruits|static/img/produc...|{\"min\":0.2,\"max\":...| 8000|\n| 2| Banana| Fruits|static/img/produc...|{\"min\":0.15,\"max\"...|10000|\n| 3| Avocado|Vegetables|static/img/produc...|{\"min\":0.7,\"max\":...| 5000|\n| 4| Bread| Bread|static/img/produc...|{\"min\":3.0,\"max\":...| 2000|\n| 5| Milk| Dairy|static/img/produc...|{\"min\":2.5,\"max\":...| 1000|\n| 6|Orange Juice| Beverages|static/img/produc...|{\"min\":3.25,\"max\"...| 1000|\n| 7| Chips| Snacks|static/img/produc...|{\"min\":0.25,\"max\"...| 5000|\n| 8| Red Pepper|Vegetables|static/img/produc...|{\"min\":0.5,\"max\":...| 1000|\n| 9| Lettuce|Vegetables|static/img/produc...|{\"min\":0.2,\"max\":...|10000|\n| 10| Tomato|Vegetables|static/img/produc...|{\"min\":0.3,\"max\":...|10000|\n| 11| Strawberry| Fruit|static/img/produc...|{\"min\":2.0,\"max\":...|10000|\n| 12| Eggs| Eggs|static/img/produc...|{\"min\":3.0,\"max\":...|10000|\n+----------+------------+----------+--------------------+--------------------+-----+\n\n+--------------------+--------+----------+--------+------------+\n| date_time|store_id|product_id|in_stock|retail_price|\n+--------------------+--------+----------+--------+------------+\n|2024-09-29 07:29:...| DAL| 3| 1834| 1.86|\n|2024-09-29 07:29:...| DAL| 2| 6580| 0.23|\n|2024-09-29 07:29:...| DAL| 1| 6899| 0.38|\n|2024-09-29 07:29:...| DAL| 9| 6936| 0.36|\n|2024-09-29 07:29:...| DAL| 8| 68| 0.98|\n|2024-09-29 07:29:...| DAL| 10| 5998| 0.47|\n|2024-09-29 07:29:...| DAL| 11| 6498| 3.5|\n|2024-09-29 07:29:...| DAL| 7| 1927| 0.72|\n|2024-09-29 07:29:...| DAL| 12| 7081| 3.09|\n|2024-09-29 07:29:...| DAL| 5| 574| 3.94|\n|2024-09-29 07:29:...| NYC| 2| 6615| 0.28|\n|2024-09-29 07:29:...| NYC| 7| 1719| 0.68|\n|2024-09-29 07:29:...| NYC| 12| 7218| 4.1|\n|2024-09-29 07:29:...| NYC| 11| 7019| 2.38|\n|2024-09-29 07:29:...| NYC| 6| 637| 4.44|\n|2024-09-29 07:29:...| NYC| 4| 643| 3.16|\n|2024-09-29 07:29:...| NYC| 10| 7033| 0.36|\n|2024-09-29 07:29:...| NYC| 5| 757| 3.11|\n|2024-09-29 07:29:...| NYC| 1| 7410| 0.25|\n|2024-09-29 07:29:...| NYC| 9| 6904| 0.32|\n+--------------------+--------+----------+--------+------------+\nonly showing top 20 rows\n"]}],"execution_count":5,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"1f672306-d3c7-4f1a-89f7-0851e8a90082"},{"cell_type":"markdown","source":["##### Demonstrate the impact order date on the sales for all sales in Chicago.\n","1. Filters sales data for the Chicago store.\n","2. Computes total sales per order by multiplying price and quantity.\n","3. Groups and sums daily sales data, then resamples it to monthly totals.\n","4. Converts data to Pandas and ensures order_date is in datetime format.\n","5. Plots the monthly sales trend over time, showing the impact of order date on sales in Chicago."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"54f2e3b3-4c12-4a3c-a6b3-44b4ca0cd519"},{"cell_type":"code","source":["import pandas as pd\n","import matplotlib.pyplot as plt\n","\n","# Filtering Chicago data\n","sales_chicago_df = ordersDf.filter(ordersDf.store_id == 'CHI')\n","\n","# Creating a 'sales' column by multiplying price and quantity\n","sales_chicago_df = sales_chicago_df.withColumn('sales', sales_chicago_df['price'] * sales_chicago_df['quantity'])\n","\n","# Selecting relevant columns: order_date, sales\n","sales_chicago_df = sales_chicago_df.select('order_date', 'sales')\n","\n","# Converting the DataFrame to Pandas\n","sales_chicago_pd_df = sales_chicago_df.toPandas()\n","\n","# Confirming that 'order_date' is in datetime format\n","sales_chicago_pd_df['order_date'] = pd.to_datetime(sales_chicago_pd_df['order_date'])\n","\n","# Group by 'order_date' and sum the sales\n","sales_chicago_pd_df = sales_chicago_pd_df.groupby('order_date')['sales'].sum().reset_index()\n","\n","# Resample the data to get monthly sales\n","sales_chicago_pd_df.set_index('order_date', inplace=True)\n","sales_chicago_monthly = sales_chicago_pd_df['sales'].resample('MS').sum().reset_index()\n","\n","# Plot sales over time\n","plt.figure(figsize=(12, 6))\n","plt.plot(sales_chicago_monthly['order_date'], sales_chicago_monthly['sales'], marker='o')\n","\n","# Adding labels and title\n","plt.xlabel('Order Date')\n","plt.ylabel('Total Sales')\n","plt.title('Impact of Order Date on Sales in Chicago')\n","\n","plt.show()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":9,"statement_ids":[9],"state":"finished","livy_statement_state":"available","session_id":"1aeb6edd-3450-4a72-a646-81cab3450974","normalized_state":"finished","queued_time":"2024-11-04T16:00:45.5593816Z","session_start_time":null,"execution_start_time":"2024-11-04T16:00:45.9707825Z","execution_finish_time":"2024-11-04T16:00:55.1084841Z","parent_msg_id":"07537c0d-3bf2-49e4-a350-205625e0c308"},"text/plain":"StatementMeta(, 1aeb6edd-3450-4a72-a646-81cab3450974, 9, Finished, Available, Finished)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"
","image/png":"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iIio0jxQ52DFZRV+js3AY62wjNL2ViIMay5FiK8MHlJxOY+wZmNgiIiIiIiIiIgq3PV0LRZHqfDLdTWyhS0QgqutBT7ylWF4cykcWHK+TDAwREREREREREQV5mxSNhYqlNgVp4HAivNoZC/GOH97DGxiBxtLJpQuSwwMEREREREREVG5MhgMOBSfhYWXlDj6IFtwv1Z1rBAql6FXA1uIWXK+XDAwRERERERERETlQqc3YNvtTCxSqKBIEV5yvpOHBKFyGV51Z8n58sbAEBERERERERGVKbVOjw3X1FgapUKcSljJeQsR0LuBLcbLZXjOmSXnKwoDQ0RERERERERUJlKz9IiIUSE8JgOPNMIySkvEwLtN7DDW3x7etRimqGg840RERERERET0TO6pdFgercKaWDUydMJSSteyFmFECylG+cjgZseS85WFgSEiIiIiIiIiKpUraVosUqjw6w01BMaD4G5ngdG+MgxtLkUta5acr2wMDBERERERERFRiZxMzMJChQp772oE92la2xJj/WUY0NgOEjETSlcVDAwRERERERERUbH0BgP239NgkUKFE4nCS863cbHCeLk9grxsYMEKY1UOA0NEREREREREVCit3oAtNzOxWKFETJpOcL8u9SQIbWmPDm7WLDlfhTEwRERERERERET5ZOYAK2MzER6bhnsZwkrOi0VA30a2GCe3h9zJqpxHSGWBgSEiIiIiIiIiMkrW5GC5Qo2IK7ZI16kF9bEVizC4mR3G+MnQ0J6hhuqEs0VEREREREREuKPSYWmUCuuuqpGZYwBQ/OVfDtYijPSRYZSvFM42LDlfHTEwRERERERERGTGolK0WKxQYuutTOQILDlfXyrGaD8ZhjSzg8yKJeerMwaGiIiIiIiIiMyMwWDAP4nZWHhJiQP3swT3a+FgifFye/TztoWVBRNK1wQMDBERERERERGZCb3BgD13NFikUOJ0klZwv5dcrTFeLkOgJ0vO1zQMDBERERERERHVcNk5Bmy6ocaSKBWupgsvOd+tnhU+bVUbL7lJynF0VJkYGCIiIiIiIiKqoZRaPVbHZmD5ZRUS1HpBfSxFQHADCd5yTEOnFnVgY8OgUE3GwBARERERERFRDfMwMwfh0SpEXMlAerawjNJSSxGGNLPDaD8ZXCx1uHs3tZxHSVUBA0NERERERERENcStxzosiVJh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Tp48WSNjDRgwQP7+/jXSFwAAuHzc6noCAAAAl0NpaakSExO1fPly+fr6qm/fvoqMjNTp06f1+eef65lnntGbb76pNWvWKDIysq6nW6N69eqlG2+8UZKUn5+vjIwMff311/roo480e/ZszZ07V3fccUfdThIAANQJEkMAAMApzJgxQ8uXL9e1116rt99+W02bNrU/V1ZWphdffFEvvfSShg0bpq1bt6pRo0Z1ONuadcstt2jy5MkOj5WVlWnVqlV68skn9cADD6hRo0bq06dPHc0QAADUFW4lAwAAV7yDBw/qtddeU0BAgN59912HpJAkubq66umnn9Zf/vIX/fLLL1qwYIHD87GxsYqNjVVubq6eeOIJRUdHq0mTJlq1apW9zcqVK9WtWzeFhoYqOjpa06ZNO++taXl5eZo1a5ZuvPFGhYWFKSIiQnfeeae+/vrrSm0rbtMqKirSCy+8oGuuuUZBQUGaPXv2Rb8mrq6uuvfee/XKK6+orKxMzzzzjGw2m/35n3/+WdOmTdPNN9+sVq1aKTQ0VF26dNFzzz0ni8Xi0Je/v7927txp//8Vf+Lj4x3a7d27V/fff7/at2+v4OBgxcTE6PHHH1dOTs5FrwMAAFwarhgCAABXvNWrV6u8vFxjx45VSEjIOds9/vjjWrt2rVatWqVnnnnG4bni4mINGjRIFotFt956q9zd3e19vfTSS5o1a5ZCQkJ07733yt3dXR988IH2799f5TgnT57U7bffrtTUVHXr1k19+vTR6dOn9e9//1txcXFavny5Bg4cWOm4e+65R3v37lWfPn0UEBCgli1bXvyL8n9GjBih2bNnKzU1VSkpKYqOjpYkbdy4UW+99ZZ69uypHj16qLy8XLt379bcuXO1c+dO/fvf/5a7u7sk6cknn9Tq1auVnp6uJ5980t53bGys/f//+9//1n333SdXV1fddtttatasmfbv36+lS5fq888/12effcYeRQAA1AESQwAA4Iq3a9cuSWf22jmfdu3aKTw8XBkZGTpy5Iiuuuoq+3OZmZmKjo7Wxx9/LG9vb/vjv/zyi1566SU1bdpU27ZtU3BwsCRp6tSp+tOf/lTlOE888YRSU1O1cOFCjR492v748ePH1adPHyUkJKhv377y8vJyOO7YsWPauXOnAgICqvcCnIeLi4u6deum3377Td999509MTRixAg9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"},"metadata":{}}],"execution_count":6,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"82b2d558-6189-4236-86d0-dd1fcb70a487"},{"cell_type":"markdown","source":["### Step 3: Statistical Analysis\n","1. Simulates Sales Data: Generates 36 months of random sales data to simulate monthly sales values.\n","2. Decomposes Time Series: Uses seasonal_decompose from statsmodels to break down the sales data into trend, seasonality, and residual components.\n"," - Trend: Shows the long-term movement in sales, whether increasing, decreasing, or stable.\n"," - Seasonality: Reveals recurring patterns or cycles within specific time intervals (like monthly or yearly).\n"," - Residual (Noise): Represents random fluctuations in the data that cannot be explained by trend or seasonality.\n","3. Organizes Data for Plotting: Prepares labels and corresponding data for the time series components.\n","4. Plots Components: Creates subplots to visualize seasonality, trend, residuals, and observed sales data, making it easier to analyze patterns in the simulated data."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"2012132c-890d-4803-b1ab-aac47bccb7f8"},{"cell_type":"code","source":["import statsmodels.api as sm"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":11,"statement_ids":[11],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:11:09.3863545Z","session_start_time":null,"execution_start_time":"2024-11-02T23:11:09.9853625Z","execution_finish_time":"2024-11-02T23:11:10.3651072Z","parent_msg_id":"3eafa0af-e142-40f7-8fc5-00a8404b59a4"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 11, Finished, Available, Finished)"},"metadata":{}}],"execution_count":9,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e1188c21-b4d9-4b45-91ee-8fe49ba78162"},{"cell_type":"code","source":["import pandas as pd\n","import numpy as np\n","\n","# Simulate additional monthly sales data for testing\n","dates = pd.date_range(start='2023-01-01', periods=36, freq='MS') # Extended to 36 months for more data\n","np.random.seed(42) # For reproducibility\n","sales = np.random.rand(36) * 100 # Random sales data\n","\n","# Create a DataFrame with the simulated data\n","simulated_sales_df = pd.DataFrame({'order_date': dates, 'sales': sales})\n","\n","# Decompose the time series into its components using statsmodels\n","import statsmodels.api as sm\n","result = sm.tsa.seasonal_decompose(simulated_sales_df['sales'], model='additive', period=12)\n","\n","# Labels and corresponding data for plotting\n","components = [('Seasonality', result.seasonal),\n"," ('Trend', result.trend),\n"," ('Residual', result.resid),\n"," ('Observed Data', simulated_sales_df['sales'])]\n","\n","# Create subplots in a grid\n","import matplotlib.pyplot as plt\n","fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(12, 7))\n","plt.subplots_adjust(hspace=0.8) # Adjust vertical space\n","axes = axes.ravel()\n","\n","# Plot the components\n","for ax, (label, data) in zip(axes, components):\n"," ax.plot(data, label=label, color='blue' if label != 'Observed Data' else 'purple')\n"," ax.set_xlabel('Time')\n"," ax.set_ylabel(label)\n"," ax.set_xlabel('Time', fontsize=10)\n"," ax.set_ylabel(label, fontsize=10)\n"," ax.legend(fontsize=10)\n","\n","plt.show()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":12,"statement_ids":[12],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:11:16.0894261Z","session_start_time":null,"execution_start_time":"2024-11-02T23:11:16.6780856Z","execution_finish_time":"2024-11-02T23:11:17.8287048Z","parent_msg_id":"87050ac5-3ebb-4738-ba9a-e82d9101e432"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 12, Finished, Available, Finished)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"
","image/png":"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CAwMxOPHj7Fr1y7s3LkTI0eOxIwZMwDYf8xhQJOBTz/9FDt37sTt27eRmJgIf39/vPHGGwgPD0e1atWc3Twil1CpUiVER0dLPnfhwgWULFkSAHD+/HlMmzYNZ8+ehUKhQN26dTFr1iyEhITkZHOJXEZGfSd//vwYPnw4Ll68iJiYGBiNRpQoUQKtW7dGeHg4a2lQntKqVSucPn3a6vNxcXGpf+Z4Q/ScLX0nLi6O4w3RCzZv3owtW7bg+vXrePr0KdRqNcLCwtCrVy907tw5zWvtOeYwoCEiIiIiIiIicjLWoCEiIiIiIiIicjIGNERERERERERETsaAhoiIiIiIiIjIyRjQEBERERERERE5GQMaIiIiIiIiIiInY0BDRERERERERORkDGiIiIiIiIiIiJyMAQ0RERERERERkZMxoCEiIiJ6SUREBOrUqePsZhAREVEeIsTFxYnObgQRERFRTvHz80v3+a5du2LevHnQ6/UICAjImUYRERFRnqdwdgOIiIiIctK1a9dS/7xz505ERETg7NmzqY95eXnBx8fHGU0jIiKiPIxLnIiIiChPKVSoUOqXr6+vxWP58+e3WOI0ZMgQdOvWDQsWLECZMmUQFBSEyMhIGAwGTJkyBcHBwQgNDcWmTZvS/Kz79++jb9++KFmyJEJCQtC1a1fcvn07R39fIiIicg8MaIiIiIhscPLkSTx48AD79u3D7NmzERkZic6dO8PPzw9HjhxB3759ER4ejrt37wIANBoN2rRpA7VajX379mH//v3w8fFBx44dodfrnfzbEBERkathQENERERkAz8/P8yZMwdlypRBz549UaZMGWg0GowdOxalS5dGeHg4lEolfv75ZwDAjh07IJPJsHjxYlSsWBHlypXD0qVLcffuXZw6dcrJvw0RERG5GtagISIiIrJBhQoVIJM9v7cVGBiI0NDQ1L/L5XL4+/sjJiYGAHDhwgXcvHkTxYsXT/N9dDodbt26lTONJiIiIrfBgIaIiIjIBgpF2tMmQRAkHzOZTAAAk8mEqlWrYvXq1Rbfq0CBAo5rKBEREbklBjREREREDlClShXs3LkTBQsWTC1GTERERGQNa9AQEREROcC7776LAgUKoFu3bvjxxx8RFRWFU6dOYcKECbh3756zm0dEREQuhgENERERkQOoVCrs27cPxYsXR8+ePfH6669j+PDh0Ol0yJcvn7ObR0RERC5GiIuLE53dCCIiIiIiIiKivIwzaIiIiIiIiIiInIwBDRERERERERGRkzGgISIiIiIiIiJyMgY0REREREREREROxoCGiIiIiIiIiMjJGNAQERERERERETkZAxoiIiIiIiIiIidjQENERERERERE5GQMaIiIiIiIiIiInIwBDRERERERERGRkzGgISIiIiIiIiJyMgY0REREREREREROxoCGiIiIiIiIiMjJGNAQERERERERETkZAxoiIiIiIiIiIidjQENERERERERE5GQMaIiIiIiIiIiInIwBDRERERERERGRkzGgISIiIiIiIiJyMgY0REREREREREROxoCGiIiIiIiIiMjJGNAQERERERERETkZAxoiIiIiIiIiIidjQENERERERERE5GQMaIiIiIiIiIiInIwBDRERERERERGRkzGgISIiIiIiIiJyMgY0REREREREREROxoCGiIiIiIiIiMjJGNAQERERERERETkZAxoiIiIiIiIiIidjQENERERERERE5GQMaIiIiIiIiIiInIwBDRERERERERGRkzGgISIiIiIiIiJyMgY0maDT6XDz5k3odDpnN4XIbbDfEGUN+w5R5rHfENlu4UIlSpfOl+aralUfnDold3bTiFyeo8YbhV2/Wx5gNBqd3QQit8N+Q5Q17DvZFx8P/POPDF5eIry9kfpfBc+Aci32G6KM/fqrHDNnesFoFNI8/vgx0K6dGvPn69C3r95JrSNyD44Yb3h6QkR5WlwcsGCBF65ckSEszIQePfQoU8bk7GYRUTbpdEB4uDe2bvWAKAoWz3t4mIMab28RXl4p/7V8TOrv5telDXzS+7uXFyBYNoGIyCk0GmDQIG+LcCaF0ShgzBhv3Lghw4wZOsg5oYYoxzCgIaI869kzoEULH1y9aj7zOHIE+OwzTzRokIz+/fVo0cLAu+xEbkgUgVGjvPHVV0qrr0lOFpCcDDx7ljPJSUYBUIECIlq0SEa7doYcaQ8R5V0ffeSFGzcyTl2WLvXEzZsyrF6tgY9PDjSMiNwzoDlx4gS2bduGX375Bffu3UP+/PlRtWpVTJgwAVWrVk193ZAhQ7B161aL/79MmTI4e/ZsDraYiFyNKAIjRqhSw5kXHT/ugePHPVC8uAl9++rRq5cegYGiE1pJRFnx+efKdMMZZ9BqBWi1Ap48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cXFxqX/meEP0nC19Jy4ujuMN0Qs2b96MLVu24Pr163j69CnUajXCwsLQq1cvdO7cOc1r7TnmMKAhIiIiIiIiInIy1qAhIiIiIiIiInIyBjRERERERERERE7GgIaIiIiIiIiIyMkY0BARERERERERORkDGiIiIiIiIiIiJ2NAQ0RERERERETkZAxoiIiIiIiIiIicjAENERER0UsiIiJQp04dZzeDiIiI8hAhLi5OdHYjiIiIiHKKn59fus937doV8+bNg16vR0BAQM40ioiIiPI8hbMbQERERJSTrl27lvrnnTt3IiIiAmfPnk19zMvLCz4+Ps5oGhEREeVhXOJEREREeUqhQoVSv3x9fS0ey58/v8USpyFDhqBbt25YsGABypQpg6CgIERGRsJgMGDKlCkIDg5GaGgoNm3alOZn3b9/H3379kXJkiUREhKCrl274vbt2zn6+xIREZF7YEBDREREZIOTJ0/iwYMH2LdvH2bPno3IyEh07twZfn5+OHLkCPr27Yvw8HDcvXsXAKDRaNCmTRuo1Wrs27cP+/fvh4+PDzp27Ai9Xu/k34aIiIhcDQMaIiIiIhv4+flhzpw5KFOmDHr27IkyZcpAo9Fg7NixKF26NMLDw6FUKvHzzz8DAHbs2AGZTIbFixejYsWKKFeuHJYuXYq7d+/i1KlTTv5tiIiIyNWwBg0RERGRDSpUqACZ7Pm9rcDAQISGhqb+XS6Xw9/fHzExMQCACxcu4ObNmyhevHia76PT6XDr1q2caTQRERG5DQY0RERERDZQKNKeNgmCIPmYyWQCAJhMJlStWhWrV6+2+F4FChRwXEOJiIjILTGgISIiInKAKlWqYOfOnShYsGBqMWIiIiIia1iDhoiIiMgB3n33XRQoUADdunXDjz/+iKioKJw6dQoTJkzAvXv3nN08IiIicjEMaIiIiIgcQKVSYd++fShevDh69uyJ119/HcOHD4dOp0O+fPmc3TwiIiJyMUJcXJzo7EYQEREREREREeVlnEFDRERERERERORkDGiIiIiIiIiIiJyMAQ0RERERERERkZMxoCEiIiIiIiIicjIGNERERERERERETsaAhoiIiIiIiIjIyRjQEBERERERERE5GQMaIiIiIiIiIiInY0BDRERERERERORkDGiIiIiIiIiIiJyMAQ0RERERERERkZMxoCEiIiIiIiIicjIGNERERERERERETsaAhoiIiIiIiIjIyRjQEBERERERERE5GQMaIiIiIiIiIiInY0BDRERERERERORkDGiIiIiIiIiIiJyMAQ0RERERERERkZMxoCEiIiIiIiIicjIGNERERERERERETsaAhoiIiIiIiIjIyRjQEBERERERERE5GQMaIiIiIiIiIiInY0BDRERERERERORkDGiIiIiIiIiIiJyMAQ0RERERERERkZMp7PFNrl69irt370Kv16d5vGXLlvb49kREREREREREuVq2ApqoqCh0794dV65cgSAIEEURACAIAgAgNjY2+y0kIiIiIiIiIsrlsrXEacKECShZsiT++usvqFQq/PTTT9i3bx9ee+017N27N9PfLz4+HlOnTkX79u1RunRp+Pn5ISIiQvK158+fR7t27VCsWDEEBQWhR48eiIqKknztypUrUbNmTbzyyiuoXLkyIiMjkZycnOn2ERERERERERE5QrYCmrNnz+KDDz5AwYIFIZPJIJPJUKtWLUyd+v/27jssiuvrA/h3l6X3Jop0pBeRYkdFxd67sdfYE41G/SVqjD2amMTYa4zdYOwNOyhKUUABAUEQRRHpve2+f/BKJDOLwC67C3s+z+OTOHd29qjD7OyZe89ZiaVLl9b5eJmZmTh06BBKSkrQv39/ofvFxcVh4MCBKC0txcGDB/HHH38gISEBffv2xYcPH6rtu2XLFixbtgwDBw6En58fpk+fjl9++QWLFy+uc3yEEEIIIYQQQgghDUGkJU4VFRXQ0NAAAOjp6eHt27ewsbGBmZkZXrx4UefjmZmZITk5GRwOBxkZGTh8+DDrfuvXr4eSkhJOnjwJLS0tAICbmxs8PDywbds2rF69GkBlwmfLli2YNGkSVq5cCQDw9vZGWVkZ1q5di9mzZ8Pe3r4+f3RCCCGEEEIIIYQQsRFpBo2joyOePXsGAPD09MTvv/+Ohw8fYtOmTbCwsKjz8TgcTlX9GmHKy8tx7do1DBo0qCo5A1Qmd7y9vastrbpx4waKi4sxbty4ascYN24cBAIBLl26VOcYCSGEEEIIIYQQQsRNpATN4sWLwefzAQDff/89UlJS0LdvX/j7+2Pjxo1iCfC/Xr58iaKiIjg5OTHGnJyckJiYiOLiYgBATEwMgMpE0qeaN28OfX39qnFCCCGEEEIIIYQQaRJpiVOPHj2q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"},"metadata":{}}],"execution_count":10,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"4c07f098-c85e-40bf-8e34-b3edcec1c9da"},{"cell_type":"markdown","source":["### Step 4: Model Training and Tracking"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"cedea140-767a-48da-b863-3b7366e198c9"},{"cell_type":"markdown","source":["#### Adding and massaging data.\n","1. Sets Up Date Range: Creates a 3-year monthly date range for generating sample data.\n","2. Simulates Seasonality: Adds a sinusoidal pattern to represent a recurring seasonal effect in sales.\n","3. Adds a Linear Trend: Creates an increasing sales trend over time by adding a linear component.\n","4. Introduces Noise: Adds random noise to make the data more realistic and less predictable.\n","5. Combines Components: Combines the seasonal, trend, and noise elements into a final sales dataset with a baseline value.\n","6. Scales Sales Data: Uses MinMaxScaler to scale the sales data (helpful for models like SARIMAX that require scaling).\n","7. Plots Simulated Data: Visualizes the simulated sales data over time, showing the trend and seasonality."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"f7230619-239d-4208-8b2c-80728b78497b"},{"cell_type":"code","source":["import numpy as np\n","import matplotlib.pyplot as plt\n","\n","# Let's create a sample 'simulated_sales_df' DataFrame with a trend and seasonality\n","date_range = pd.date_range(start=\"2022-01-01\", periods=36, freq='MS') # 3 years of monthly data\n","np.random.seed(42) # For reproducibility\n","\n","# Simulate a basic seasonal pattern with a sinusoidal component\n","seasonal_pattern = 10 * np.sin(2 * np.pi * np.arange(len(date_range)) / 12)\n","\n","# Add a linear trend component (e.g., increasing sales)\n","trend_component = np.arange(len(date_range)) * 5\n","\n","# Add some random noise to make the data more realistic\n","noise = np.random.normal(0, 5, len(date_range))\n","\n","# Combine these components to create the 'sales' data\n","sales_data = 50 + trend_component + seasonal_pattern + noise # Start with a base sales level\n","\n","# Create DataFrame to mimic 'simulated_sales_df'\n","simulated_sales_df = pd.DataFrame({\n"," 'order_date': date_range,\n"," 'sales': sales_data\n","})\n","\n","# Scale the sales data as done typically for SARIMAX\n","from sklearn.preprocessing import MinMaxScaler\n","scaler = MinMaxScaler()\n","simulated_sales_df['scaled_sales'] = scaler.fit_transform(simulated_sales_df[['sales']])\n","\n","# Plot the adjusted simulated data\n","plt.figure(figsize=(12, 6))\n","plt.plot(simulated_sales_df['order_date'], simulated_sales_df['sales'], label='Simulated Sales with Seasonality and Trend', marker='o')\n","plt.xlabel('Order Date')\n","plt.ylabel('Sales')\n","plt.title('Adjusted Simulated Sales Data')\n","plt.legend()\n","plt.show()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":13,"statement_ids":[13],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:11:25.6513032Z","session_start_time":null,"execution_start_time":"2024-11-02T23:11:26.1060884Z","execution_finish_time":"2024-11-02T23:11:27.1730469Z","parent_msg_id":"bbbda893-71b5-48f7-bc84-57edded8bc80"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 13, Finished, Available, Finished)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"
","image/png":"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ypXat2+f8vLyFB4erh49eujmm2+u0wk89RmXxJxolFoxJxqzbpJ3zIlS49asuvHU54fNuo5LYl40Sq2YF41ZN4l50RU1mzZtmtatW6dDhw6pqKhIzZs3V0pKiu69916dccYZdX4NjTEvEugAAAAAAAAYDHvoAAAAAAAAGAyBDgAAAAAAgMEQ6AAAAAAAABgMgQ4AAAAAAIDBEOgAAAAAAAAYDIEOAAAAAACAwRDoAAAAAAAAGAyBDgAAAAAAgMEQ6AAAAK8WERGhESNGNPYwAAAAXIpABwAAuNVnn32m66+/XsnJyYqNjVVSUpKGDRump59+WsXFxY09PJdatmyZIiIiKn5FRkaqdevW6tatm6655ho999xzys3Ndcm1RowYoYiICJc8FwAA8Hy+jT0AAADQNJSVlWnKlClavHixQkJCNGTIELVr107Hjx/Xp59+qvvvv1+LFi3SihUr1K5du8YerksNGDBA559/viSpoKBAGRkZ2rJliz744AOlpqbqiSee0KWXXtq4gwQAAIZCoAMAANxixowZWrx4sXr27KmXX35ZCQkJFW02m02zZ8/WnDlzdMUVV2j9+vUKCwtrxNG61sCBAzV58uRKj9lsNi1btkz33XefbrzxRoWFhWnw4MGNNEIAAGA03HIFAAAa3N69e/X0008rMjJSr776aqUwR5LMZrP+9a9/6corr9S+ffs0b968Su1du3ZV165dZbFYdO+99yo5OVnR0dFatmxZRZ+lS5eqT58+iouLU3JysqZPn17jLVx5eXmaOXOmzj//fMXHxysxMVF//etftWXLlip9y29nKikp0SOPPKIePXooJiZGqampp/yemM1mXXfddXrsscdks9l0//33y+FwVLT/8ssvmj59uvr376+2bdsqLi5OvXr10oMPPqj8/PxKzxUREaFNmzZV/L781y233FKp3w8//KAbbrhBHTp0UPPmzdWlSxfdc889ysnJOeXXAQAAGgcrdAAAQINbvny57Ha7JkyYoNjY2Gr73XPPPXr99de1bNky3X///ZXarFarRo0apfz8fA0bNkx+fn4VzzVnzhzNnDlTsbGxuu666+Tn56e33npLP//8s9Pr5Obmavjw4dq1a5f69OmjwYMH6/jx43r//fc1cuRILV68WH/5y1+qfN7f/vY3/fDDDxo8eLAiIyOVlJR06m/K78aMGaPU1FTt2rVLO3fuVHJysiRp9erVeumll5SSkqILLrhAdrtdX3/9tZ544glt2rRJ77//vvz8/CRJ9913n5YvX6709HTdd999Fc/dtWvXit+///77uv7662U2m3XJJZeoZcuW+vnnn7Vw4UJ9+umn+uSTT9iDBwAAAyHQAQAADW7r1q2STuwlU5OzzjpLLVq0UEZGhn799Ve1atWqoi0zM1PJyclas2aNgoKCKh7ft2+f5syZo4SEBG3YsEHNmzeXJE2dOlUXXnih0+vce++92rVrl+bPn69x48ZVPP7bb79p8ODBuvPOOzVkyBAFBgZW+rzDhw9r06ZNioyMrN8bUAMfHx/16dNHBw8e1LffflsR6IwZM0a33Xab/P39K/WfPXu2UlNT9fbbb+uqq66SJE2bNk2ff/650tPTNW3atCrXyMnJ0cSJExUTE6MPP/xQrVu3rmh74403dNNNN+mRRx7R//73P5e9LgAA0LC45QoAADS43377TZLUsmXLWvuW98nMzKzS9tBDD1UKcyTp9ddfV1lZmW699daKMEeSwsLCNGXKlCrPkZ2drbfeeksDBgyoFOZIUmxsrG6//XZlZWVp/fr1VT532rRpLg1zyrVo0UKSKt36lJCQUCXMkaSbb75ZkpyOrzqvvPKKjh8/runTp1cKcyTpiiuu0Nlnn6233nrrFEYOAAAaCyt0AACARynfR8ZkMlV6PDAwsGL1ysl++OEHSVLfvn2rtPXp06fKY99++61sNptKSkqc7oGzb98+SdKePXs0bNiwSm29evWq46uon5P3zjn5sZdfflnLly/Xrl27dPz4cdnt9or2I0eO1Pn5v/7664qP5a/vZCUlJcrOzlZ2draio6NP4RUAAAB3I9ABAAANLjY2Vrt379ahQ4d05pln1tg3IyOj4nNOFhMTUyXkkaTjx49XtDu77p/l5uZKkr744gt98cUX1Y6joKCgTs/nCuXhzMlhyr333quFCxeqVatWuuSSSxQfH1+xYmf27NkqKSmp8/OXv+aFCxfW2K+goIBABwAAgyDQAQAADe68887T559/rg0bNmjgwIHV9tu9e7cOHz6shISESvvnSFVX7JQrP948KytLiYmJldrKb/U6WbNmzSRJkyZN0sMPP1yfl1HtGE6H3W7X5s2bJUk9e/aUJB09elTPP/+8kpOTtXbtWgUHB1f0z8zM1OzZs+t1jfLXvHnzZnXu3NlFIwcAAI2JPXQAAECDu+aaa+Tj46MlS5YoKyur2n5z586VJI0dO7bOz92lSxdJqghFTubsCPKePXvKZDLpq6++qvM1GtKrr76q9PR0de7cWZ06dZIkpaWlyeFwaODAgZXCHMn5a5JOHIMuSTabrUrbOeecI0ke85oBAMDpI9ABAAAN7owzztDEiROVk5Ojq6++usr+L3a7XXPmzNGKFSvUtm1b3X777XV+7iuvvFJms1nPPPOMjh49WvH48ePHKwKik8XFxemyyy7T1q1b9dRTTzndv+brr79WYWFhPV5h/dlsNr300ku6++67ZTabNXPmzIoVQOUbF3/55ZeV9s05dOiQHnzwQafPV75Z86FDh6q0jR07Vs2aNdN///tf7dq1q0p7YWEhYQ8AAAbDLVcAAMAtHnroIR0/flwvv/yyevXqpYsvvlht27ZVXl6ePv30U+3du1ft27fX66+/XnEbVV20a9dO9957r1JTU9WvXz9deuml8vX11apVq5ScnKw9e/ZU+ZxHH31Ue/bs0fTp0/Xqq6+qd+/eCgsL06FDh7R9+3bt3btXP//8c5XVMadq/fr1Ki4uliQVFRUpIyNDmzdvVkZGhiIjI/Xss89WuhUtPj5eo0aN0qpVqzRw4EANGDBAv/32m9asWaP+/fsrLS2tyjX69++vlStXasKECbrooosUGBiozp07a+jQoYqJidHzzz+vCRMm6IILLtCQIUN05plnqqSkRAcPHtTmzZvVu3dvvfnmmy55vQAAoOGZLBZL1f+WAgAAaCDr16/X4sWLtXXrVmVlZSk4OFgdOnTQqFGjdOONN1Y5llySunbtKkn6/vvvq33epUuX6plnntG+ffvUvHlzXX755frXv/6lFi1aqF+/fnrvvfcq9S8qKtLChQv11ltvac+ePbLb7YqNjVWXLl00cuRIXXHFFfL1PfF/XyNGjNCmTZtksVjq9VqXLVum2267reLPJpNJISEhioqKUufOnTV48GBdddVVioiIqPK5+fn5mjVrllatWqXMzEy1atVKV199te688041b968ymsqKyvTf//7X7355ps6cuSIysrKdM0112jBggUVffbs2aOnnnpK69evV2ZmpoKDg5WQkKCUlBSNGTOmYg8fAADg+Qh0AAAAAAAADIY9dAAAAAAAAAyGQAcAAAAAAMBgCHQAAAAAAAAMhkAHAAAAAADAYAh0AAAAAAAADIZABwAAAAAAwGAIdAAAAAAAAAyGQAcAAAAAAMBgCHQAAAAAAAAMhkAHAAAAAADAYAh0AAAAAAAADIZABwAAAAAAwGD+Hw/R7tMxwwtIAAAAAElFTkSuQmCC"},"metadata":{}}],"execution_count":11,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"ae86a4b6-108c-4d7d-a157-58137af2824f"},{"cell_type":"markdown","source":["#### Scaling data."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e57ae0b4-e6eb-4cbb-8559-4b0046f8fd8f"},{"cell_type":"code","source":["# Scaling the sales data only if it's not already scaled properly\n","scaler = MinMaxScaler()\n","scaled_sales = scaler.fit_transform(simulated_sales_df[['sales']])\n","\n","# Update simulated_sales_df with the scaled values for the model to train on\n","simulated_sales_df['scaled_sales'] = scaled_sales"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":14,"statement_ids":[14],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:11:30.4199926Z","session_start_time":null,"execution_start_time":"2024-11-02T23:11:30.8233941Z","execution_finish_time":"2024-11-02T23:11:31.2042125Z","parent_msg_id":"f54f687a-17c0-4be0-9072-09e270f149d1"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 14, Finished, Available, Finished)"},"metadata":{}}],"execution_count":12,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"40cd93f5-b144-47f7-ba31-3ff1f692d192"},{"cell_type":"markdown","source":["#### Model training.\n","1. Define Hyperparameter Ranges: Sets ranges for SARIMAX model parameters (p, d, q) and creates combinations for both non-seasonal (pdq) and seasonal parameters (seasonal_pdq with a 12-month seasonality).\n","2. Initialize Best Model Tracking: Sets placeholders for the best AIC (model performance metric), and corresponding parameters.\n","3. Iterate Through Parameter Combinations: Tests each combination of (pdq) and (seasonal_pdq) by fitting a SARIMAX model to the scaled_sales data.\n","4. Track Best Model: If a model's AIC score is lower than the current best, updates best_aic, best_param, and best_param_seasonal to store the optimal parameters.\n","5. Print Best Parameters: Outputs the optimal (pdq) and (seasonal_pdq) parameters along with the lowest AIC score.\n","6. Fit Final Model: Fits a SARIMAX model using the best parameters found for scaled_sales."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"d6fc8522-d375-4623-9933-70528a62dd19"},{"cell_type":"code","source":["# Hyperparameter tuning for SARIMAX\n","p = d = q = range(0, 2)\n","pdq = list(itertools.product(p, d, q))\n","seasonal_pdq = [(x[0], x[1], x[2], 12) for x in pdq]\n","\n","best_aic = float(\"inf\")\n","best_param = None\n","best_param_seasonal = None\n","for param in pdq:\n"," for param_seasonal in seasonal_pdq:\n"," try:\n"," mod = sm.tsa.statespace.SARIMAX(simulated_sales_df['scaled_sales'],\n"," order=param,\n"," seasonal_order=param_seasonal,\n"," enforce_stationarity=False,\n"," enforce_invertibility=False)\n"," results = mod.fit(disp=False)\n"," if results.aic < best_aic:\n"," best_aic = results.aic\n"," best_param = param\n"," best_param_seasonal = param_seasonal\n"," except:\n"," continue\n","\n","print(f'Best ARIMA{best_param}x{best_param_seasonal}12 - AIC:{best_aic}')\n","\n","# Fit the best SARIMAX model on scaled data\n","mod = sm.tsa.statespace.SARIMAX(simulated_sales_df['scaled_sales'],\n"," order=best_param,\n"," seasonal_order=best_param_seasonal,\n"," enforce_stationarity=False,\n"," enforce_invertibility=False)\n","results = mod.fit(disp=False)"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":15,"statement_ids":[15],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:11:34.4235122Z","session_start_time":null,"execution_start_time":"2024-11-02T23:11:34.8689054Z","execution_finish_time":"2024-11-02T23:11:40.6091719Z","parent_msg_id":"e904a639-f4d2-4105-b337-b1fbc5c2d795"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 15, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stderr","text":["/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n"]},{"output_type":"stream","name":"stdout","text":["Best ARIMA(1, 0, 0)x(0, 0, 0, 12)12 - AIC:-109.61193341586926\n"]}],"execution_count":13,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"32dd0e0b-1ab0-4905-b378-f084c56ced09"},{"cell_type":"markdown","source":["#### Model diagonostics for SARIMAX model.\n","- Residuals Plot: Look for randomness around zero. Any patterns or trends indicate model inadequacy.\n","- Histogram and KDE Plot: Check for normal distribution centered around zero. Skewness or heavy tails suggest poor fit.\n","- Q-Q Plot: Points should lie along the 45-degree line. Deviations indicate non-normal residuals.\n","- Correlogram (ACF Plot): Significant autocorrelations suggest the model is not capturing temporal dependencies."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e87f82b8-a4fc-4830-9759-408b7ea4c7a3"},{"cell_type":"code","source":["# Print model summary\n","print(results.summary())"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":16,"statement_ids":[16],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:11:44.7803494Z","session_start_time":null,"execution_start_time":"2024-11-02T23:11:45.2423172Z","execution_finish_time":"2024-11-02T23:11:45.6235055Z","parent_msg_id":"91c5bfe2-a049-4c57-b802-ebccc6e63d17"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 16, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":[" SARIMAX Results \n==============================================================================\nDep. Variable: scaled_sales No. Observations: 36\nModel: SARIMAX(1, 0, 0) Log Likelihood 56.806\nDate: Sat, 02 Nov 2024 AIC -109.612\nTime: 23:11:45 BIC -106.501\nSample: 0 HQIC -108.538\n - 36 \nCovariance Type: opg \n==============================================================================\n coef std err z P>|z| [0.025 0.975]\n------------------------------------------------------------------------------\nar.L1 1.0369 0.013 77.347 0.000 1.011 1.063\nsigma2 0.0023 0.001 2.333 0.020 0.000 0.004\n===================================================================================\nLjung-Box (L1) (Q): 1.08 Jarque-Bera (JB): 2.87\nProb(Q): 0.30 Prob(JB): 0.24\nHeteroskedasticity (H): 1.15 Skew: -0.13\nProb(H) (two-sided): 0.81 Kurtosis: 1.62\n===================================================================================\n\nWarnings:\n[1] Covariance matrix calculated using the outer product of gradients (complex-step).\n"]}],"execution_count":14,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"f78183d9-b20c-4955-b961-90ab290e03cc"},{"cell_type":"code","source":["# Plot diagnostics\n","results.plot_diagnostics(figsize=(15, 12))\n","plt.show()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":17,"statement_ids":[17],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:11:48.1730157Z","session_start_time":null,"execution_start_time":"2024-11-02T23:11:48.7278865Z","execution_finish_time":"2024-11-02T23:11:49.8751635Z","parent_msg_id":"4d7101d1-4424-46d0-bb74-a0012e7b1bdd"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 17, Finished, Available, Finished)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"
","image/png":"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nMpYFfB1fVDdlMd4IR+fv6goNek9qqxq2mdfIJDILaX4+HiPv7UruO3U02wblF1cXJz69eun119/XTabTREREZUdUrURHx8vyfNvodPT02UymVSrVq2KDqtaGzhwoKKioqjFVYJp06bp6aef1iOPPKLbbrutcDuv2fLhbXy94XXrn8aNG6tx48aSpL59+0qSHnvsMV1zzTW8doFqrGXLlpo5c6ZffQveI0782dv7Rt26dcs30CBwKmMllf7zq6o71fFCPr6/o6LUtPeosqppn32BQCK3lJKTk7V48WI5nc4idXZSUlIkSW3atKms0KqtE1fNRPlp1qyZIiIiCl+7J0pJSVHz5s0VHh5eCZFVb4ZhyGymPLk306ZN07Rp0zRx4kSNGzeuSBuv2VPna3x94XVbeh06dNDrr7+uXbt26eyzz+a1C1RTDRo00A033FAuxzrxfaM6fpk9lbEq6+dXVVaer62ajO/vqAg18T2qvFT3z75A4FtZKQ0YMEBZWVlatmxZke0LFixQYmKiOnXqVEmRVU8ZGRn6/PPP1b59e77klrOQkBBdcskl+uijj5SZmVm4fe/evaW6lQv+W7p0qXJycnif8OKpp57StGnTNH78eE2cOLFYO6/ZU1PS+HrD67Zs1q5dK7PZrKSkJF67APxy4vsG/lHWzy9A4vs7Ao/3qFPDZ1/pMSO3lPr06aNevXpp7NixyszMVLNmzbR48WKtXLlSc+bMkcViqewQq6xbb71Vp512ms4555zCxc5efPFFHTp0SC+//HJlh1flrFixQjk5OYVJg19++UVLly6VlP86joyM1AMPPKCLLrpIw4cP17333qvc3FxNnTpVderU0ZgxYyoz/KBW0tgeOXJEI0eO1JAhQ9S8eXOZTCZ98803mjVrltq0acPsCg9eeOEFTZkyRb1791a/fv20YcOGIu3nnnuuJPGaLSN/xnfPnj28bsvgnnvuUUxMjDp27Kh69erp6NGjWrp0qT744APdfffdhTMLeO0CKODv+wb8vz7AP/z5DlCT8P29bHgd+Yf3KP/x2Vd+TBkZGUZlB1HVZGVl6YknntCSJUuUnp6uli1bauzYsRo6dGhlh1alzZgxQx988IF2796t7Oxs1a5dW+eff77Gjh2rDh06VHZ4VU779u21d+9ej21bt25V06ZNJUlbtmzRo48+qg0bNigkJEQ9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Nmw4lWHzy4wZMwr//dxzzykmJqbEfcaPH6/WrVtLkpYuXarff/+92sQBAABQVu+++64kyWQyeUwKltaiRYvUqVMnvfjii0pJSdHx48eVm5urPXv26L333lO/fv00YcIEud3uEo/15ptvqnfv3nrnnXe0e/du5ebmnlLfLVu2qFOnTpowYYLWrFmjQ4cOyeFw6OjRo/r66681YcIE9ejRo8TrYV9eeOEFde3aVXPnztVvv/2m7Oxs5eTk6Pfff9cbb7yh7t27F7mG9GT8+PG65pprtGrVKh09elQ2m02///67XnjhBfXs2VNbt271O5709HT16dNHEydO1Pfff6+jR48W+x5yzz336JprrtGrr76qzZs369ixY3I6nUpPT9cPP/yg6dOn69xzz9W3337r1znfe++9wlJi+/btU25urv7880+9/PLL6tevX2EyuuC70tKlS/XXX38pLy9Pu3fv1syZM9W/f39lZWX5/TgBlB9KKwCoMu655x69/vrrOn78uP7973/roosuKtNxtm3bpuHDh+uvv/4qsj01NVWff/65Pv/8c73++utasGBBiYtDbNy4UVdffbWOHDlS4nl/+uknXXnllYUXR1L+7XJLlizR8uXLtXjxYnXp0kVr1qzR9ddfr+PHjxf2y83N1aJFi7RixQr973//U3JycrHjr127VgMHDiy23W63648//tAff/yh9957T/fee68effTREuMti23btmnz5s2SpI4dO+r888/3a7+QkBCNHDlS48aNk9vt1rvvvqtJkyZV+TgAAADK6vjx4/rpp58kSaeffrqaN29+SsdbuXKlbrvtNhmGoYiICI0ePVq9e/dWWFiYNm/erOeee05//fWX5syZo/DwcD3++ONej7V582YtXLhQiYmJGjNmjDp27CjDMPT999/LarWWuu+OHTs0YMAAZWVlKSoqSjfffLPOPfdcNW7cWMePH9eqVav06quvaufOnRo6dKhWr16tWrVqlerxv/nmm3rkkUckSXFxcbrnnnsKy7WtX79ezz33nNLT0/XYY48pJiZGt956a7FjPP/883rttdckSQ0bNtS9996rDh06KC8vT1988YVeeukljRgxQjabza+Y7rzzTqWkpGjYsGEaMmSIGjRooAMHDsjlchX2cblcSkpK0oABA9SxY0eddtppCgkJ0Z49e7RmzRq98847SktL03XXXaf169erXr16Xs/3888/a/HixWrevLnGjBmjtm3bKjMzU++8844WLlyo3377TY888ogGDhyoRx55ROeee65uu+02tWzZUkePHtUrr7yi5cuX68cff9TTTz+tyZMn+zv8AMoJiVwAVUbt2rU1evRoTZ8+XT/88IP+97//6bLLLivVMQ4cOKCBAwcqLS1NknTVVVdp2LBhqlevnv744w/NmTNH3377rdavX69hw4bp008/lcVi8XisgoW0bDabxo4dq169eik6Olq//PKLmjRpUqSvzWbTddddJ7vdrkmTJqlbt26yWCxauXKlnn32WeXk5Oj222/XkiVLdP311ysmJkYPPvigOnXqJKfTqWXLlmnWrFnKyMjQ3XffrZUrVxaLx+VyKSoqSn379lXPnj3VsmVLxcTE6MiRI9q+fbteeeUV7d27VzNmzFCLFi103XXXlWrs/LFu3brCf5f2ubnssss0bty4YsepynEAAACUVUpKSmFC71QXYXU4HLrnnnsKk7jLli3TueeeW9jesWNHDRkyRJdccol27typF198UVdddVXhXWUn27Fjh1q3bq1PP/1UtWvXLtzeuXPnUvc1DEO33nqrsrKy1KZNGy1ZskQJCQlFjnHBBRfoiiuuUP/+/fXHH3/ohRde0MMPP+z3409LS9NDDz0kSapbt66WL19eJDHeuXNnDR48WH379tWhQ4f0yCOPaNCgQapfv35hn9TUVE2dOlWS1KRJE61cubJIe9euXdWnTx8NHDhQdrvdr7i2bdumGTNm6KabbircdvJz/cADDygpKUkmk6nI9nPOOUeDBw/WLbfcon79+unIkSN65ZVXfI7LTz/9pPPOO08ffvihIiMjC7f37NlTeXl5Wrp0qRYvXqwVK1Zo0KBBeuONN4p8F7rwwgt1ySWXaMOGDXr77bf18MMPKySEtBJQkSitAKBKufPOOwsvAKdMmeKzBIInDz74YGESd9q0aXr11VfVp08fnX322RoyZIj+97//aciQIZKk77//vvA37p6kpaUpIyNDn3zyiSZNmqQePXronHPO0dVXX60zzzyzSN8jR44oKytLX3zxhcaOHavzzjtPnTp10sSJE/Xvf/9bkrRnzx717dtX9erV05o1azRq1Ch16tRJ559/vqZMmaK77rpLUv4sYE+3bLVv317btm3TG2+8oZtuukndu3fX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FUsqt27dWlJ+vVpfC4pt27bNr/q4/jixtq+3JK70T51hANUfiVwAVVZoaKgmTJggSdq3b19hTVtvCi7gJGnjxo0++xZcwErFL+KC0Yn1f70tqiYF/iIvOTlZ55xzjqT8Mfz+++/92s/pdGru3LmFP19++eXVIg4AAIBTcd1116lBgwaSpLlz52rNmjV+77t06VJlZ2dLknr16lW4/Z133vG6z7fffqtffvml2D6B1L9//8J/P/vsswE5R8Fjyc7O1gcffOC135IlS3T8+PEi+xS44IILJEnHjx/3OVHgvffeO9VwCxWUnfBVD/jgwYP69NNPy+2cAIIbiVwAVdrw4cMLfzs9Y8YMn3Vfe/ToUXibvK8L2OPHj+vDDz+UlH9rfVnqb1W0E2vm+rrQKynZXR7uvffewn//3//9n1+Ljc2YMaNwZeD27duXyxeHYIkDAACgrCIiIjRnzhxZLBa53W5dc801PhORUv7iYePHj9eIESMKZ472799fjRo1kiTNnDnTY83djIwM/d///Z+k/DJkI0eOLNfH4s3AgQMLJ07Mnz+/xJnHu3bt0vvvv1+qc1x77bWFC+NOnjzZ45oSu3fv1iOPPCIpf9xvuOGGIu3XXHNN4Z1ujzzyiMc7/L7//nu99tprpYrNl+bNm0uSfv/9d3333XfF2nNycjRy5MiArH0BIDiRyAVQpVksFk2cOFFSfjmE+fPne+3boEEDDRw4UJK0du1aj0lNwzA0btw4paWlSZJuv/32AERd/gou8iR5HYO5c+eWusxAWQwaNEjDhg2TJKWkpOiqq67yumqv2+3WCy+8oH//+9+S8p/PGTNmVKs4AAAATkXPnj314osvymq1KicnRzfffLMuuugiPf/881q9erW2bNmib775Ru+9955uu+02nX322cWSiaGhoXr++edlMpmUnZ2t/v3768knn9T69eu1adMmzZ07Vz169NCOHTskSXfddVdhyYNAM5vNeuONNxQbGytJmjhxogYMGKB58+Zpw4YN2rJli1avXq0XXnhBl19+uTp06KBly5aV6hx16tQpvM5LTU1Vr169NHPmTG3YsEEbNmzQCy+8oF69ehVeKz7xxBOqX79+kWMkJibq/vvvl5RfBuLCCy/Ua6+9pk2bNmn9+vV68sknNXjwYDVo0KBwYeVTXRjt6quvlpR/rTps2DA9++yz+uabb/TDDz8UPmdr167V+eeff0rnAVB1sIILgCrviiuu0DPPPKNt27aVuPjAlClTtGbNGqWlpWncuHH6/vvvddVVV6lOnTratWuXXnnllcJas507d9att95aEQ/hlJ111llKTk5WSkqK3njjDR07dkzDhg1TgwYNtG/fPi1cuFBLly7V+eefr2+//Tbg8cyYMUNHjhzRF198ofXr1+vcc8/VtddeqwsvvFAJCQnKysrSzz//rPnz5xfWIZPyb6fr1KlTtYsDAADgVFxzzTVq1qyZJkyYoB9//FGbNm3Spk2bvPavU6eO7r///sLkqCT17t1bc+bM0V133aXs7Gw9/fTTevrpp4vtO3LkSE2ePDkQD8OrM844QytWrNCIESO0Y8cOff311/r666+99i9L7d4bb7xRx48f12OPPaa0tDRNmjSpWB+LxaKHH37Y63eAe++9V3v37tUbb7yhffv2afz48UXa69Spo7feekvXX3+9JCk8PLzUcZ6oQ4cOeuCBBzR16lQdO3ZMjz/+eLE+Y8aMUZs2bSrkGh9A5SORC6DKM5lMevDBBwsXg/AlMTFRy5Yt0/Dhw7Vv3z699957HutYdenSRfPnz5fFYglEyOXOZDJp9uzZGjRokDIyMvTBBx8Uu+0uOTlZb775ZuFCDYEUFRWl//73v3riiSf0yiuv6Pjx45o1a5ZmzZrlsX9cXJxmzpypQYMGVcs4AAAATtX555+vNWvWaMWKFfr888/17bffKjU1VRkZGYqMjFRiYqLOPvts9evXT5dddpnHJOJVV12lLl26aPbs2friiy+0d+9e2e121a9fX127dtXNN9+s8847rxIeXX4y95tvvtGHH36ojz76SJs2bdKRI0fkdDpVu3ZttWjRQueee64uueQSde3atUznuPvuu9WvXz+98sor+uqrr7R//35J+d8Revbsqdtuu63IuhonM5lMmjFjhvr06aPXXntNmzdvls1mU8OGDdWnTx/dfffdatSoUWGd3RMT6WV1//3365xzztHs2bO1adMm5eTkqF69eurQoYNuvvlm9erVS+++++4pnwdA1WDKyMgwKjsIAPBk7dq1haUQnn32Wd18880++1988cVFFin7/vvvva7ump2drddff12ffPKJfvnlF2VlZSk+Pl5nnXWWrrrqKl155ZVeb4UaPXq0FixYoMaNG+unn37yGZO/ffv3769vvvlG3bp10yeffOK1X/v27bV3715dc801HpORe/fu1YwZM7RixQodPHhQ0dHRat68uS6//HKNHDlS4eHhiouLk5R/UfjAAw8U2f/dd9/VnXfeKUnaunVrudQH3r17txYuXKhVq1Zp165dOnr0aJGVfpOSkrR69WrVrl37lM9VFeIAAABA9bVv3z61bdtWUn494pNr7QLAqSCRCwCocC6XS9dee60+++wzSfm10ApqHdfEOAAAAFA9zJw5s7Bsw7p16woXcgOA8kAiFwBQKQoW2ihYNXnGjBm66aabamwcAAAACG42m00ZGRlKTEz02L5161YNGDBAmZmZat++vdauXVvBEQKo7syVHQAAoGYqqF972mmnSZLGjRtX6hWIq1McAOCvzMxMTZo0SVdccYVatGihuLg4TZ061e/9Dx8+rNGjR6t58+ZKTExUnz59tGbNGo99v/zyS/Xp00eJiYlq3ry5Ro8ercOHD5fXQwGAKiUtLU1nn322br75Zs2fP18bNmzQ1q1b9fnnn+u+++7TJZdcoszMTJlMJv373/+u7HABVEMsdgYAqDQJCQlavHhx4cJsv//+u+x2u6xWa42MAwD8kZaWpjfffFPt2rVT//799fbbb/u9b15engYPHqxjx45p2rRpqlevnl599VUNHTpUS5YsUffu3Qv7fv3117ryyivVt29fzZ8/X4cPH9bkyZM1ePBgrV69WmFhYYF4eAAQ1PLy8jwuLFwgNDRUM2bMUM+ePSs4MgA1AaUVAAAAgCrEMPIv300mk44ePaoWLVp4XMDSk9dee03jx4/X8uXL1blzZ0mS0+lU9+7dFRUVpVWrVhX2veiii5STk6Ovv/5aISH58z++++479evXT88884xuueWWADw6AAheTqdTn3zyiVasWKFNmzbpyJEjSk9PV0REhBo3bqwLLrhAt912m5KSkio7VADVFDNyAQAAgCrEZDKVed+PP/5YLVu2LEziSlJISIiGDRumxx9/XPv371fDhg21f/9+bdq0SY8++mhhEleSzjvvPJ1++un6+OOPSeQCqHFCQkI0ePBgDR48uLJDAVBDUSMXAAAAqCG2b9+utm3bFttesG3Hjh2F/U7cfnLfgnYAAABUHBK5AAAAQA2Rlpam2rVrF9tesC0tLa3I3976FrQDAACg4pDIBQAAAGoQX6UZTm7z1vdU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yvv73yniAgAAeElubq7mzJmjLl26KCIiQvHx8UpLS3Pp2KFDhyo0NLTK/zIyMqqNHTNmTH29NAAAAFSDGblNmPHzz2WZMkV+R444jSvu1095q1fLERPjmcQAAABQqZtuuklHjhzRggUL1LFjR23evFmTJ0+W3W7XDTfc4PTYJ598Ujk5OeW25eXlaezYsbrssssUERFRbl9MTIyee+65cttatGhRNy8EAAAANUYhtymy22V+9lkFLlggQ35+lWGOgADlP/SQCqdNk4xM3gYAAPCmHTt2aPfu3Vq7dq3Gjh0rSRowYIBOnTqlefPmafTo0TKZTFUe36VLlwrbXnrpJRUVFemmm26qsM9iseiqq66quxcAAACAWqE618QYTp1S8MiRssyZ47SIa/vVr5S7Z48Kp0+niAsAAOADtm3bppCQEF3/iwVnJ0yYoDNnzujw4cM1PueGDRsUEhKi0aNH11GWAAAAqC/MyG0qHA75v/SSLHPnyvDjj1WHmUwquOceFdx7r+Tv78EEAQAA4Mzx48fVuXNn+fmVfwvfrVu3sv19+vRx+XxffvmlDh48qJtvvlkhISEV9p84cUIxMTHKyclR27ZtNWbMGM2aNUsWi8Wl8+c7mTRQFwoLC8v9Cd/AffFd3Bvfxb3xXdwb39TY7ktgYKDLsRRymwDD2bOy3HWX/P/5T6dxtthYWZ95RrYrrvBQZgAAAHBVZmamYipZs6Bly5Zl+2tiw4YNklRpW4W+fftq9OjRio2NVX5+vnbu3Kmnn35aBw8e1LZt22R04RNb6enpstlsNcrJHT9fpA2+g/viu7g3vot747u4N76pMdwXk8mkDh06uBxPIbeR83vtNVn+/GcZz51zGlcwZYry58+XXJxhAQAAAPft379fw4cPdyl237596tmzpyTJYDBUGeds3y8VFxcrNTVVXbt2rbQP7oMPPlju68GDBys6OloPPfSQXn/9dZdyj4qKcjkfdxQWFiojI0MREREym831ei24jvviu7g3vot747u4N76pKd+XRlHIzcnJ0RNPPKGPPvpIH374oc6dO6f77rtPc+fOden4jRs36o477qh032effVZhBd8GITtbljlzZP7b35yG2du0Ud6qVbINHOihxAAAABAbG6vly5e7FNu2bVtJUlhYWKWzbrOysiT9b2auK3bs2KGMjAzdddddLh8zbtw4PfTQQzp8+LBLhdyafEywNsxms8euBddxX3wX98Z3cW98F/fGNzXF+9IoCrmZmZl64YUX1L17dw0dOlTr16936zyrVq1S586dy20LCwurixQ9yrRnj4LuuEPG06edxhX+/veyLl4stWjhmcQAAAAgSWrdurVuvvnmGh0TFxentLQ0FRcXl+uTe+zYMUlS165dXT7Xhg0bZDabNX78+BrlIMmltgoAAACoe42ikBsdHa2vv/5aBoNB586dc7uQGxcXp8svv7yOs/OgvDwFzp+vgOeecxpmDw+XddkyFQ8d6qHEAAAAUFvDhg3TunXrtHXrVo0ePbpse2pqqiIjI9WrVy+XzpORkaGdO3dq+PDhNZq0kJqaKkkuXwcAAAB1q1EUcmvSD6yxMh0+LMuUKTL9979O44qGDZN12TI5Lr7YQ5kBAACgLiQlJSkxMVEzZ85UTk6O2rdvr7S0NO3atUvPPvusTCZTWez06dOVmpqqo0ePKjo6utx5UlNTVVxcXOWM4AMHDujJJ5/UsGHDFBMTo/z8fO3atUsvvPCCBgwYoGuvvbZeXycAAAAq1ygKuXVl3Lhx+uGHH9S8eXPFx8fr/vvvV1xcnEvH5ufn13N2VSgsVPBTTyl4+XIZ7PYqw+zNmiln0SLljx0rGQySh/ItLCws9yeqxli5hnFyHWPlGsbJNYyT6xgr55paH7O6tmHDBi1cuFCLFi1SVlaWYmNj9fzzz2vMmDHl4mw2m2w2mxwOR4VzvPjii4qOjtavf/3rSq/RunVrmUwmPfHEEzp37pwMBoM6dOig+++/X9OnT6e1AgAAgJcYsrOzK767a8DOnTunjh071mixs127duntt99Wr1691KxZMx07dkzLli1Tdna2tm/frh49elR7jq+++ko2m6226ddI4H//qw7z5yvo88+dxv141VU6MW+eilq39lBmAAAAFZlMJnXo0MHbaaCRyM/P16lTp9S2bVt+QeBDuC++i3vju7g3vot745ua8n3xuRm5+/fvd2kVXEnat2+fevbsWetrDho0SIMGDSr7un///ho8eLD69++vRYsWlfUDcyYqKqrWebjMZlPQmjUKWbJEBiezfRwWi3IefFDWP/xBrb00c6KwsFAZGRmKiIiQ2Wz2Sg4NBWPlGsbJdYyVaxgn1zBOrmOsAAAAANQHnyvkxsbGavny5S7Ftm3btt7yaNeuna6++modPnzYpXhP/QbAeOKELNOmye/gQadxxb16ybpmjRydOskXfjdhNpub3G9J3MVYuYZxch1j5RrGyTWMk+sYKwAAAAB1yecKua1bt65y4QVPczgcvtMDzOGQ/7p1sjzwgAwXLlQd5uengjlzVPDnP0t+Pnd7AQAAAAAAALiBSl8VTp48qUOHDmngwIHeTkWGM2dkmTFD/jt3Oo2zxcUpLyVF9l/9ykOZAQAAAAAAAPCERlPI3blzp/Ly8pSTkyNJ+uyzz7RlyxZJUlJSkoKCgiRJ06dPV2pqqo4eParo6GhJ0siRI9WvXz9169atbLGz5cuXy2Aw6IEHHvDOC/qJ/z/+ocCZM2XMzq4yxmEwqPDOO5V///0SH+EEAAAAAAAAGp1GU8idOXOmTp06Vfb1q6++qldffVWS9MEHH6hdu3aSJJvNJpvNJofDURYbFxenV155RStXrpTValV4eLgSEhI0e/ZsderUyaOvo5QhM1OBs2bJ/I9/OI2zxcTIunq1bP36eSgzAAAAAAAAAJ7WaAq5H330kUtxKSkpSklJKbdt8eLF9ZGS2/x27pTlzjtl/O47p3EFf/iD8hculEJCPJQZAAAAAAAAAG9oNIXcRiE3V4EPPqiAF15wGmZv3VrWFStUnJTkmbwAAAAAAAAAeBWFXB9hOnhQlqlTZTp50mlc4Zgxyl+6VI6WLT2TGAAAAAAAAACvo5Drbfn5Cly0SOYVK2T4Wd/eX7KHhir/ySdVNGaMB5MDAAAAAAAA4Aso5HqR8YMPFDRlikzHjzuNK0pKknX5cjkiIz2UGQAAAAAAAABfQiHXG4qLFfCXvyhgyRIZiourDHMEB8u6aJGKbr5ZMhg8mCAAAAAAAAAAX0Ih18OMX3why9Sp8jt82Glccd++yktJkSMmxjOJAQAAAAAAAPBZRm8n0GTY7TI/+6xCBgxwWsR1mM2yLlyoC9u2UcQFAAAAAAAAIIkZuZ6Rna3gSZPkt3ev0zBbz57KW7NG9rg4DyUGAAAAAAAAoCFgRq4nNG8u2WxV7naYTMqfNUu5u3ZRxAUAAAAAAABQAYVcTzAalbdqlRzNmlXYZevUSRf+/W8VPPigZDZ7ITkAAAAAAAAAvo5Croc42rWTddGictsKbrtNufv2ydarl5eyAgAAAAAAANAQ0CPXg4omTlTRtm0yffyx8lavlm3gQG+nBAAAAAAAAKABoJDrSQaDrKtWyeHnJ4WGejsbAAAAAAAAAA0EhVwPc1x8sbdTAAAAAAAAANDA0CMXAAAAAAAAAHwchVwAAAAAAAAA8HG0VvAAm92hAxmFyrDaFGExqV+EWSajwdtpAQAAAAAAAGggKOTWs60nrZpzKFvpefaybVFBRiX3CdWIGIsXMwMAAAAAAADQUNBaoR5tPWnVpN2Z5Yq4knQmz65JuzO19aTVS5kBAAAAAAAAaEgo5NYTm92hOYey5ahkX+m2ue+cl81eWQQAAAAAAAAA/A+F3HpyIKOwwkzcn3NIOn3BpgMZhZ5LCgAAAAAAAECDRCG3nmRYbXUaBwAAAAAAAKDpopBbTyIspjqNAwAAAAAAANB0UcitJ/0izIoKMspQxX6DpEuCTeoXYfZkWgAAAAAAAAAaIAq59cRkNCi5T6gkVSjmln69uHcLmYxVlXoBAAAAAAAAoASF3Ho0IsaidYlhigwqP8xRwSatSwzTiBiLlzIDAAAAAAAA0JD4eTuBxm5EjEVDowN1IKNQGVabIiwl7RSYiQsAAAAAAADAVRRyPcBkNCghMsDbaQAAAAAAAABooGitAAAAAAAAAAA+jkIuAAAAAAAAAPg4CrkAAAAAAAAA4OMo5AIAAAAAAACAj6OQCwAAAAAAAAA+jkIuAAAAAAAAAPg4CrkAAAAAAAAA4OMo5AIAAAANQE5OjubNm6dRo0apY8eOCg0N1eLFi2t0jrNnz2rq1Knq0KGDIiMjlZSUpL1791Yau2fPHiUlJSkyMlIdOnTQ1KlTdfbs2bp4KQAAAHADhVwAAACgAcjMzNQLL7yggoICDR06tMbHFxQUaOTIkdq3b5+Sk5P10ksvKTw8XGPGjNGbb75ZLvbNN9/U2LFjFR4erpdeeknJycnau3evRo4cqYKCgrp6SQAAAKgBP28nAAAAAKB60dHR+vrrr2UwGHTu3DmtX7++Rsdv2LBBx44d044dO9S7d29JUkJCguLj4zV//ny98cYbZbHz5s1Tp06dtH79evn5lfzI0K5dO11zzTV68cUXNXny5Lp7YQAAAHAJM3JR70wmk7dTaDAYK9cwTq5jrFzDOLmGcXIdY4X6YDAYZDAY3D5+27Ztio2NLSviSpKfn59uvPFGvffee0pPT5ckpaen68iRIxo3blxZEVeS+vTpo06dOmnbtm3uv4g6xt8138R98V3cG9/FvfFd3Bvf1FTvCzNyUa8CAwPVoUMHb6fRIDBWrmGcXMdYuYZxcg3j5DrGCr7q+PHj6tu3b4Xt3bp1kyR9+umnioqK0vHjx8tt/2XsoUOH6jdRF/F3zTdxX3wX98Z3cW98F/fGNzXl+8KMXAAAAKAJyMzMVMuWLStsL92WmZlZ7s+qYkv3AwAAwLOYkQsAAAB42P79+zV8+HCXYvft26eePXvWyXWdtWb45b6qYmvT3gEAAADuo5ALAAAAeFhsbKyWL1/uUmzbtm3r5JphYWGVzqbNysqS9L8ZuGFhYZJUZWxlM3UBAABQ/yjkAgAAAB7WunVr3XzzzR69ZlxcnI4dO1Zhe+m2rl27lvvz2LFjGjx4cIXY0v0AAADwLHrkAgAAAE3AsGHD9Pnnn+vw4cNl24qLi7Vp0yb16tVLkZGRkqSoqChdeeWV2rRpk2w2W1nsu+++qy+++MLllhAAAACoW4bs7GyHt5MAAAAAUL2dO3cqLy9POTk5mj59uq6//nqNGjVKkpSUlKSgoCBJ0vTp05WamqqjR48qOjpaklRQUKBf//rXysnJ0fz58xUeHq61a9dq+/btevXVVxUfH192nf3792vUqFEaMmSIbr31Vp09e1YPP/ywmjdvrt27dysgIMDzLx4AAKCJY0Yu6lROTo7mzZunUaNGqWPHjgoNDdXixYtdPn7jxo0KDQ2t9L+MjIx6zNyzajtOknT27FlNnTpVHTp0UGRkpJKSkrR37956yti7cnNzNWfOHHXp0kURERGKj49XWlqaS8c2tmeqNmPRlJ4Zyf2xamzPTHVq+/2oKT1XtRmrpvZcof7MnDlTkyZN0vTp0yVJr776qiZNmqRJkybp7NmzZXE2m002m00Ox//mbAQEBGjLli2Kj4/X7NmzNX78eGVkZGjz5s3liriSlJCQoJdfflkZGRkaP368Zs+erfj4eG3ZssXrRdza/FuI+rF3717dcccduuqqqxQVFaWuXbvqd7/7nd5//31vp4ZKrF+/XqGhobrkkku8nQokHTx4UDfccIPatWun1q1b64orrtDjjz/u7bSatA8++EC///3v1aVLF0VGRuqqq67SkiVLlJeX5+3UmpSavPd+//33NXLkSF1yySWKjo7WxIkTdfLkSc8m7CH0yEWdyszM1AsvvKDu3btr6NChWr9+vVvnWbVqlTp37lxuW+nCG41BbcepoKBAI0eO1Pnz55WcnKzw8HA999xzGjNmTIUZNY3BTTfdpCNHjmjBggXq2LGjNm/erMmTJ8tut+uGG25w6RyN5Zlydyya2jMj1f65aSzPTHVq8/2oqT1XdfFvXFN5rlB/PvroI5fiUlJSlJKSUmF7q1attGbNGpfOkZiYqMTExBrl5wl18b4Adeuvf/2rMjMzNWXKFF166aU6d+6cVq5cqUGDBiktLU0DBw70dor4SXp6uh588EFFRkbqxx9/9HY6Td7LL7+s22+/XaNGjdKaNWsUHByskydP6syZM95Orcn69NNPdc0116hTp05avHixwsLCdODAAT3++ON6//33lZqa6u0UmwxX33t//vnnGj58uLp3767/+7//U35+vhYvXqxrr71W+/fv18UXX+zhzOsXhVzUqejoaH399dcyGAw6d+6c24XcuLg4XX755XWcne+o7Tht2LBBx44d044dO9S7d29JJTNn4uPjNX/+fL3xxhv1kbZX7NixQ7t379batWs1duxYSdKAAQN06tQpzZs3T6NHj5bJZKr2PI3hmarNWDSlZ0aqm+emMTwzrqjN96Om9lzVxb9xTeW5AupLXb0vQN1aunSpwsPDy2377W9/qyuuuEJPPfUUhVwfcvfdd6tfv35q2bKltm7d6u10mrT09HT9+c9/1h/+8Ac9+eSTZdsHDBjgxaywefNm5efna8OGDWrfvr0kaeDAgcrIyNALL7yg7OxshYaGejfJJsLV996LFi2S2WzW3//+dzVv3lySdNlll+nKK6/UihUr9PDDD3sy7XpHawXUKYPBIIPB4O00fF5tx2nbtm2KjY0tK5xIkp+fn2688Ua99957Sk9Pr4s0fcK2bdsUEhKi66+/vtz2CRMm6MyZM+UWbGnsajMWTemZkXhuaqI234+a2nPFv3GA9/H93Tf9sogrSSEhIbr00kt1+vRpL2SEyvz973/XgQMHyhUN4T3r16/XhQsXdNddd3k7FfyMn1/JfMfSgmCpFi1ayGg0yt/f3xtpNUmuvPcuLi7Wv//9b40YMaLcPYuOjlZCQoK2bdtW32l6HIVc+KRx48YpLCxMMTExmjhxoo4dO+btlHzK8ePH1a1btwrbS7d9+umnnk6p3hw/flydO3cu+we1VOlrPX78uEvnaQzPVG3Goik9M1LdPDeN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rCwaGhqYP39+u+5LREREREREHj8KckXk/8KwYcMoLCzEZDKRk5NDSUkJRqMRHx8foqOjmThxot34cePG4e3tTUpKCt988w1//vknfn5+LFiwgPfff/++d0ROnTqVwMBAUlNTKSoqIjs7G3d3d/r06cPs2bOJi4uzjXVycmLr1q0sXbqUjIwM2+FrEyZMuGeQC/Dmm2+Sm5tLSkoKR44cITs7m549exIYGMjUqVNt49577z1cXFzYtGkTaWlpeHh4EBkZyZIlS3jnnXfu677u5bXXXqO8vJx169aRk5PDl19+aduF6urqislkIjY21uG6rl27sm/fPhYvXkxBQQHl5eUEBweTlZWF2Wx2CHKjoqJsh4Lt3LmTrl27EhYWxrZt21o8VOx+bNy4kcWLF5OZmcnVq1exWCwEBwffd5BrMBhYv349kZGRbNmyhf3793P9+nW8vLx4+umnWbFiBa+++ioAfn5+fPDBBxw+fJj8/HwuXbpEz549eeGFF5g9ezbh4eEP5N5ERERERETk8WGoq6uzPOxFiIhIx2fdhWs2m1m1ahUzZ8582EsSEREREREReWwoyBURkVa7du0aUVFR/Pzzz6xbt85uJ7KIiIiIiIiI/HtUWkFERFrNzc2N9PR0tm7dytmzZ7l27Rpubm4Pe1kiIiIiIiIijzztyBURERERERERERHp4Do97AWIiIiIiIiIiIiISMsU5IqIiIiIiIiIiIh0cApyRURERERERERERDo4BbkiIiIiIiIiIiIiHZyCXBEREREREREREZEOTkGuiIiIiIiIiIiISAenIFdERERERERERESkg1OQKyIiIiIiIiIiItLBKcgVERERERERERER6eD+AzDRUnjmj86yAAAAAElFTkSuQmCC"},"metadata":{}}],"execution_count":15,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"f01ecd42-e187-428a-bca2-099c25ffd318"},{"cell_type":"markdown","source":["#### Plotting forecasted data."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"16c243a6-90c4-4c9d-844d-e3330d2c2a71"},{"cell_type":"code","source":["# Forecasting the next 12 months\n","forecast_steps = 12\n","forecast = results.get_forecast(steps=forecast_steps)\n","forecast_index = pd.date_range(start=simulated_sales_df['order_date'].iloc[-1] + pd.DateOffset(months=1), periods=forecast_steps, freq='MS')\n","forecast_scaled = forecast.predicted_mean.values.reshape(-1, 1)\n","\n","# Apply inverse transformation to get the forecast back to original scale\n","forecast_original_scale = scaler.inverse_transform(forecast_scaled)\n","forecast_df = pd.DataFrame({'order_date': forecast_index, 'forecast': forecast_original_scale.flatten()})\n","\n","# Plot the observed data and forecast\n","plt.figure(figsize=(12, 6))\n","plt.plot(simulated_sales_df['order_date'], simulated_sales_df['sales'], label='Observed Data', marker='o')\n","plt.plot(forecast_df['order_date'], forecast_df['forecast'], label='Forecast', marker='x')\n","plt.xlabel('Order Date')\n","plt.ylabel('Sales')\n","plt.title('Forecasted Chicago Sales')\n","plt.legend()\n","plt.show()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":19,"statement_ids":[19],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:12:07.2622138Z","session_start_time":null,"execution_start_time":"2024-11-02T23:12:07.7666218Z","execution_finish_time":"2024-11-02T23:12:08.8432013Z","parent_msg_id":"0318e3c6-6334-4e2d-bed4-3ebbba47dfa8"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 19, Finished, Available, Finished)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"
","image/png":"iVBORw0KGgoAAAANSUhEUgAABG0AAAJECAYAAACsHdkDAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAADAvElEQVR4nOzdd3xT1fsH8E+SNkn3ohNaCsguyEZG2SBQKYKKIspQNjhAEFBARUZFviiggrL3nrJXgTJEtmgru8xSSvfKaHJ/f/TX2NAk3WnafN6vFwr3nHvvk5xeaJ6e8xxRUlKSACIiIiIiIiIisijisg6AiIiIiIiIiIjyYtKGiIiIiIiIiMgCMWlDRERERERERGSBmLQhIiIiIiIiIrJATNoQEREREREREVkgJm2IiIiIiIiIiCwQkzZERERERERERBaISRsiIiIiIiIiIgvEpA0RERERERERkQVi0oaIiIjKNVdXV7i6umLOnDllHQqAkonn/v37uuusX7++BKOjshYSEgJXV1eEhISUdShERFQO2JR1AEREZL0iIiLQq1evAvefNGkSpkyZUooREQFZWVnYu3cvjh49igsXLiAuLg4pKSlwcnKCr68vmjZtip49e6Jr166wseG3UuVJUlIS1q9fj6NHjyIyMhKJiYmQSqWoVKkSvLy80KBBA7Rp0watW7eGj49PWYdLRETEpA0RERHl7/79+3j55ZcBAD///DMGDBhQxhGVjgMHDuDLL7/E3bt387QlJiYiMTERkZGRWLt2LSpXrowvv/wS7777bhlESoV16NAhjB49GvHx8XrHVSoV0tLSEB0djT///BPLly+Hl5cXbt68WUaREhER/YdJGyIisggffvghPvzwQ5N9PD09zRQNWaMffvgBM2bMgCAIAIDg4GD07NkTdevWhZubG5KSknDv3j0cOnQIR48exePHjzF58uRSSdpUrVoVSUlJJX5da3Xu3Dm89957UKvVEIvF6Nu3L3r06IFq1apBLBYjISEB169fR3h4OE6fPl3W4RIREekwaUNERBahUqVKqFevXlmHQVZq06ZN+OabbwAAHh4eWLFiBdq3b5+nX/v27TF48GBER0fjq6++Qnh4uLlDpSL48ssvoVarIZFIsHXrVnTq1ClPn06dOuGTTz5BXFwcdu3aZf4giYiIDGDShoiIiKxaTEwMPvvsMwCAvb09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3Lt3D1u3bsWiRYvw5Zdf5rlOUlISpk+fjgMHDiA1NRX16tXDhAkT0LNnT71+CoUCS5cuxaZNm/Dw4UNoNBp4enqiadOmGD9+POrXr6/Xf9++ffj1119x7do1KBQKVK9eHe+++y5Gjx4NieS/qXXr16/HmDFj8PPPP6NSpUr48ccfcf36dbi5uWHJkiUICQnBe++9h59++ilP7I8fP0aDBg3Qtm1b7NmzR3c8NTUVixYtwp49exAdHQ2pVIrmzZtjwoQJaNWqVZ7rREVF4euvv8aZM2cgFovRsmVL3ddxSWndujV27NiBNm3aYOHChRg8eDCqVKkCIDthunLlShw+fBh3795FfHw8PDw80L59e0yePBnVqlXTXSckJARnzpwBAPTq1Ut33N/fH9evXweQvVxu8+bNOH/+PGJiYgAANWvWxODBgzF48OASfV1ERERERFROKTMhW/49bM8fz9MkylJDsLG12oQNYIFJG2M8PDwQFxcHIHs5zqFDh/DOO+/ozdoICAhAcHAw9u7dq/uwe/ToUSgUCgwYMEDvegMGDMC3336Lffv2lXrS5kJc6S3DupOiwR3kTeqYy4YNG6DVajF48OA8CZvcJk6ciK1bt2L9+vV5kjZqtRq9e/eGQqFA//79kZycjB07dmDAgAH49ddf0a9fP13fUaNGYefOnahfvz7effddyGQyPHr0CBEREejUqZNe0mbGjBmYP38+KleujNDQUDg5OeHs2bOYNm0aLl68iNWrV+eJc/fu3Th+/DheffVVfPjhh0hLS0Pr1q0REBCAPXv2YN68eZDL5XrnbN26FVqtFm+//bbuWGJiInr27ImoqCi0atUKnTp1QkpKCvbv349evXph1apVeO2113T9IyMj0b17d6SlpaFXr16oUaMGLl26hO7du+dJRBXXSy+9hD59+mDTpk3Yt28fRowYASB79trs2bMRHByM1157Dfb29rh58ya2bduGw4cP4+TJkwgICAAAvPvuuwCAM2fOoH///rrjLi4uuvssWLAAd+/eRfPmzeHn54fk5GQcPXoUn376KW7duoVZs2aV6OsiIiIiIqLyRRT7CPKF0yB5ZLjupoDsxI3t7jVWm7ix2KSNVquFVqtFUlISdu3ahWPHjuH7778HANy7dw+ZmZkGP8zWr18f4eHhUCgUkMvliIqKAgDUq1dPr5+Pjw88PDx0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Yvz48ahbty6aNGmC1atXl0iQRERERGQ+311Nxc7oTINtnSvL8G1zFzNHREREZJ2KnLT53//+h2+++QZOTk66YzNmzMDKlSuRlpaGR48eYdy4cTh58mSJBEpEREREpW/XvUyEXTW8U1QtFxus6OAOG267TUREZBZFTtpcunQJwcHBEImy/9FWq9VYv349mjZtilu3buHatWuoVKkSfvnllxILloiIiIhKz9XnKoyKMLxTlKtUhE1dPODCnaKIiIjMpsj/6sbFxaFKlSq6P1+8eBGpqakYMmQI5HI5fH190bNnT/z9998lEigRERERlZ6nGRq8eywemRohT5uNCFjd0QPVnblTFBERkTkVOWkjFouhVCp1fz537hxEIhGCg4N1x9zd3REfH1+8CImIiIioVGVmCXj3WDyeZBjeKWruK65o78edooiIiMytyEmbgIAARERE6P68e/duVK1aFQEBAbpjT548gbu7e/EiJCIiIqJSIwgCPjqTiMvPDe8UNayuAz6ow52iiIiIykKRkzZvv/02/v77b3Tp0gU9evTA9evX8cYbb+j1+euvv1C9evViB0lEREREJUujFRARo8SQE4nYdtfwTlEd/GSY04I7RREREZWVIi9MHj58OC5fvozdu3dDEAR06dIFn332ma798uXLiIqKwpQpU0okUCIiIiIqGXuiMzH5fJLR5VAA8JKzDVZxpygiIqIyVeSkjUwmw8qVK5GSkgKRSKS39TcAVK1aFadOndJbLkVEREREZWtPdCYGhScgb7nh/7hIRdjUxR2uMu4URUREVJaKvQWAs7OzweMeHh7w8PAo7uWJiIiIqJjS1Fpcea7GhWdKzL2WajJhAwDL27vhJRdbs8RGRERExhU7aXPt2jVs374dN2/eRGZmJnbv3g0AePDgAS5duoQOHTrAzc2t2IESERERUf60goAbSVm4GKfS/YpKyoI2v0xNLjIJZ9gQERFZgmIlbaZPn46ffvoJgpD9XYBI9N+aZ0EQMHToUMycOROjRo0qXpREREREBI1WwNlYFWIzNfC2k6C1txQJSm2uBI0al5+rkKouRIbGgNhMTQlFTERERMVR5KTNunXrsGjRInTv3h3Tpk3D9u3b8cMPP+jaq1atiqZNm+LAgQNM2hAREREVk6HiwRIRoClefsYgbztJyV+UiIiICq3Ic1+XL1+O2rVrY+3a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daO+voE6t37U2DdQ59aN+vqGllbnVrcQscNRsXeSwWBQly5dFBwcrF27dtVot2vXLiUnJ7eoYgEAAAAAAN/RqkIbs9mstWvXqnfv3goKCpKfn5/GjRunNWvWqKCgoKpdZmamNm/erAkTJniwtwAAAAAAALVrsY9H3XDDDerQoYP69+9ftRDxokWLdPToUS1evLiq3ezZszV69GhNnDhRM2bMUElJidLT0xUTE6Pp06d78A4AAAAAAABq12JDm5SUFK1atUovvviiioqKFBUVpSFDhui5557TgAEDqtqdfvrpeu+993TvvfdqypQp8vPzU2pqqpYvX67Y2FgP3gEAAAAAAEDtWmxoM2PGDM2YMcOltv369dO7777r5h4BAAAAAAA0nVa1pg0AAAAAAEBrQWgDAAAAAADghQhtAAAAAAAAvBChDQAAAAAAgBcitAEAAAAAAPBChDYAAAAAAABeiNAGAAAAAADACxHatGImk8nTXYAbUV/fQJ1bN+rrG6hz60eNfQN1bt2or29oiXU2mM1mh6c7AQAAAAAAgOqYaQMAAAAAAOCFCG0AAAAAAAC8EKENAAAAAACAFyK0AQAAAAAA8EKENgAAAAAAAF6I0AYAAAAAAMALEdq4waeffqpp06Zp0KBBSkxMVI8ePXTVVVdp586dNdru3LlTF110kdq3b6+kpCRNnjxZGRkZ1dr8/PPPuvvuu3X22WcrKSlJnTt31tixY/Xuu+/WON/q1at1/fXXq3///mrbtq169+6tP//5z9q3b1+D7sGVfknS4sWLNXnyZPXp00eRkZEaP358g67TEvlKfZcvX67IyMhaP5544okGXbOl8WSdN23apIsvvljdu3dXfHy8TjvtNE2YMEHr1q1r0D0wjmvnK/X19XEsebbWJ3vooYcUGRmpoUOHNugeGMu185X6+vpY9mSd6/rcZ2VluXwPjOO6+UqNGcue/5r9/vvv64ILLlDHjh2VmJioIUOGaOnSpS7fgyfGMqGNG7z44os6cOCApk6dqpUrV2revHnKzs7WmDFj9Omnn1a127t3ryZMmCCr1aqXXnpJixYt0r59+3T++ecrOzu7qt2GDRu0bt06paWl6eWXX9aSJUuUnJysKVOmaP78+dWu/c9//lPFxcW69dZb9eabb+ruu+/Wt99+q7PPPlu7d+92qf+u9kuSXnrpJWVmZmrEiBGKjY09hc9ay+Er9R07dqzWr19f42PUqFGSpAsvvPBUPo1ez5N1zs3NVffu3TV37lytWrVKTzzxhPz9/XXFFVfo9ddfd6n/jOO6+Up9fX0cS56t9Ym+/fZbLVy4UPHx8Q3qP2O5br5SX18fy95Q56effrrG5z86Otql/jOO6+crNWYse7bOTzzxhK6++mr17NlTL730kl599VVdf/31slqtLvXfU2PZYDabHad0BtRw7NgxxcXFVXutsLBQAwYMUI8ePaqSv2uvvVabN2/W119/rfDwcEnSgQMHNHDgQP3lL3/R/fffL0nKyclRdHS0DAZDtXNOnDhRmzdv1i+//KLAwMBar3348GH16dNHV155pRYuXFhv/13tlyTZ7XYZjRXZ39ChQxUdHa3333/f5c9VS+RL9T1ZUVGRunXrpt69e+vDDz+s91otmSfr7ExZWZn69u2rTp06ufS5ZxzXzZfqezJfGseSd9S6vLxco0aN0rBhw/T9998rNzdX27Ztc6n/jOW6+VJ9T+ZLY9mTdV6+fLmmTZumjRs3qn///o3qP+O4fr5U45Mxlpunzjt37tTo0aN177336m9/+1uj+u+pscxMGzc4+S+iJIWFhalbt246ePCgpIpv8GvXrlVaWlpVwSUpKSlJqampeu+996pei4mJqfEXUZIGDBig4uJi5eXl1Xntdu3aKTExseradWlIvyRV/UX0Jb5U35OtWrVKhYWFuvrqq+u9VkvnyTo74+/vr4iICPn5+dXbd8Zx/XypvifzpXEseUetn3jiCeXl5emee+5pUN8Zy/XzpfqezJfGsjfUubEYx67xpRqfjLHcPHV+/vnnFRgYqBtvvLFRfffkWPbNrwoecPz4cX3zzTfq3r27JOmXX36RxWJRSkpKjbYpKSnav3+/SkpK6jzn5s2bFRsb6/Qv/4kyMjKUmZlZde26NEW/fJGv1PeVV15ReHi4Lr744nqv1Ro1d53tdrvKy8t1+PBhzZ07Vz///LOmT59ebz8Zx43jK/X19XEsNW+tf/zxRz366KN6/PHHFRYW1qB+MpYbx1fq6+tjubm/Zk+cOFHR0dHq3LmzJk+erF27drnUT8Zx4/lKjRnLzVPnrVu36vTTT9fq1at1xhlnKDo6Wj179tR9993n0uNRnhzLhDbN5LbbblNxcbFmzpwpqWJNA0mKioqq0TYqKkoOh0Nms7nW8y1btkyff/65Zs6cKZPJVGu78vJyTZ8+XWFhYfrLX/5Sbz9PtV++yhfqu3fvXm3fvl2XXnqpQkJC6r1Wa9Tcdb788ssVGxurHj166Nlnn9WLL76osWPH1ttPxnHj+EJ9GccVmqvWdrtd06dP14QJE3Teeec1uJ+M5cbxhfoylpuvzgkJCZo5c6aeeuoprVmzRnfddZe+/vprnXvuufruu+/q7SfjuPF8ocaM5ear8+HDh7V//37dcccduummm/TOO+/o//7v/7Rw4UJNmzat3n56cizXPw8bp+yhhx7SypUrtWDBAvXr16/aMWfTueo7tn79es2cOVMXXXSRbrrpplrf73A4NH36dG3btk3Lli1Thw4dqo7Z7XbZ7fZq1zrxL3Vj+uWrfKW+//73vyVJ11xzTa3vbc08UecFCxbo+PHjOnLkiFauXKnrrrtOzzzzjC677DJJjOOm5Cv19fVxLDVvrZ9++mnt27dPr776ap19Yiw3HV+pr6+P5eas85gxYzRmzJiqPw8fPlznnXeehg8frrlz51bVn3HctHylxozl5quz3W5XQUGB/vWvf+nSSy+VJI0YMUJFRUV65plnNHv2bCUnJ3vlWGamjZvNmzdPjz76qO65555qz89VrkRemdidKC8vTwaDQRERETWOffLJJ7r66qs1atQoLVmypNa/GA6HQ7fccotWrlypxYsX19hibNq0aYqNja36SEtLO6V++SpfqW9ZWZlee+019erVq9ELtLVknqpz165dNWDAAF1wwQVaunSpzj77bM2cObPqGwnjuGn4Sn19fRxLzVvrzMxMzZ07V3fccYf8/f1lNptlNptls9lkt9tlNptlsVgkMZabiq/U19fHsqe+Zp+oU6dOGjJkiHbs2FH1GuO46fhKjRnLzVvnyvOec8451V4/99xzJUnffPONJO8cy8y0caN58+Zp3rx5mjVrlm699dZqx7p06aLg4GCnz0ru2rVLycnJCgoKqvb6J598okmTJmn48OFatmyZAgICnF638gf65cuXa+HChZo4cWKNNrNmzao2OCqfw25Mv3yVL9X3o48+0rFjx3Tbbbc57VNr5qk6OzNgwAB9/PHHys7OVnx8POO4CfhSfX15HEvNX+uMjAxZLBbNmjVLs2bNqnHezp07a+rUqVV9YiyfGl+qry+PZW/6mu1wOKotNMo4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t2+XVLG2S11OP/10tWvXTocOHdJvv/2mDh06VB3LyspSSkqK1q5dq+Dg4KrX9+/frwULFigxMVGffvqp4uLiJEmzZs3SOeec4/Q6t99+u3bv3q1FixZp8uTJVa8fPXpUo0eP1t///neNGTNGQUFB1d53+PBhbdmyRVFRUQ37BNTBaDRq6NChOnDggL766quq0GbixImaNm2aAgICqrWfP3++0tPT9fbbb+uKK66QJM2ePVuff/65MjMzNXv27BrXyM3N1dSpUxUbG6uPPvpIHTt2rDr25ptv6oYbbtDDDz+sRx55pMnuCwAAnDoejwIAAG539OhRSVL79u3rbVvZJisrq8axBx54oFpgI0lvvPGGysvL9Ze//KUqsJGk8PBwzZw5s8Y5cnJytGrVKp199tnVAhtJio+P1y233KLs7Gxt2rSpxntnz57dpIFNpXbt2klStceUEhMTawQ2knTjjTdKktP+1ebVV19Vfn6+5syZUy2wkaTLLrtMffv21apVqxrRcwAA4E7MtAEAAF6lcl0Xg8FQ7fWgoKCqWSgn+v777yVJw4YNq3Fs6NChNV776quvZLPZVFpa6nRNmv3790uSfvrpJ40bN67asYEDB7p4Fw1z4lo2J772yiuvaMWKFdq9e7fy8/Nlt9urjh85csTl8+/YsaPq18r7O1FpaalycnKUk5OjmJiYRtwBAABwB0IbAADgdvHx8dq7d68OHjyoP/zhD3W2PXToUNV7ThQbG1sjyJGk/Pz8quPOrnuyvLw8SdIXX3yhL774otZ+FBUVuXS+plAZwJwYmNx+++1asmSJOnTooPPPP19t27atmnkzf/58lZaWunz+yntesmRJne2KiooIbQAA8CKENgAAwO3OPPNMff755/r00081cuTIWtvt3btXhw8fVmJiYrX1bKSaM28qVW4Nnp2draSkpGrHKh/LOlGbNm0kSdOnT9dDDz3UkNuotQ+nwm63a+vWrZKkAQMGSJKOHTumF154QSkpKVq/fr1CQkKq2mdlZWn+/PkNukblPW/dulU9e/Zsop4DAAB3Y00bAADgdldddZWMRqNefvllZWdn19ru0UcflSRNmjTJ5XP36tVLkqqCjxM52757wIABMhgM+vLLL12+hju99tpryszMVM+ePdWjRw9JUkZGhhwOh0aOHFktsJGc35NUsYW4JNlsthrHzjjjDEnymnsGAACuIbQBAABud9ppp2nq1KnKzc3VlVdeWWM9FrvdrgULFmjlypXq0qWLbrnlFpfPffnll8tkMmnx4sU6duxY1ev5+flVIdCJEhIS9Mc//lHbt2/XU0895XQ9mR07dqi4uLgBd9hwNptN//73v3XrrbfKZDJp7ty5VTN5KhcL/s9//lNtHZuDBw/qvvvuc3q+ygWSDx48WOPYpEmT1KZNGz344IPavXt3jePFxcUEOgAAeCEejwIAAM3igQceUH5+vl555RUNHDhQ5513nrp06aKCggJt2LBB+/btU9euXfXGG29UPfLkiuTkZN1+++1KT0/X8OHDdfHFF8vPz0+rV69WSkqKfvrppxrveeyxx/TTTz9pzpw5eu211zR48GCFh4fr4MGD2rlzp/bt26c9e/bUmOXSWJs2bVJJSYkkyWKx6NChQ9q6dasOHTqkqKgoPfvss9UeG2vbtq3S0tK0evVqjRw5UmeffbaOHj2qtWvXasSIEcrIyKhxjREjRujdd9/Vtddeq3PPPVdBQUHq2bOnxo4dq9jYWL3wwgu69tprddZZZ2nMmDH6wx/+oNLSUh04cEBbt27V4MGD9dZbbzXJ/QIAgKZhMJvNNf97CQAAwE02bdqkpUuXavv27crOzlZISIi6deumtLQ0XX/99TW29Jak3r17S5K+++67Ws+7bNkyLV68WPv371dcXJwuueQS3XnnnWrXrp2GDx+u999/v1p7i8WiJUuWaNWqVfrpp59kt9sVHx+vXr16acKECbrsssvk51fx/1vjx4/Xli1bZDabG3Svy5cv17Rp06r+bDAYFBoaqujoaPXs2VOjR4/WFVdcocjIyBrvLSws1Lx587R69WplZWWpQ4cOuvLKK/X3v/9dcXFxNe6pvLxcDz74oN566y0dOXJE5eXluuqqq/TMM89Utfnpp5/01FNPadOmTcrKylJISIgSExOVmpqqiRMnVq2pAwAAvAOhDQAAAAAAgBdiTRsAAAAAAAAvRGgDAAAAAADghQhtAAAAAAAAvBChDQAAAAAAgBcitAEAAAAAAPBChDYAAAAAAABeiNAGAAAAAADACxHaAAAAAAAAeCFCGwAAAAAAAC9EaAMAAAAAAOCFCG0AAAAAAAC8EKENAAAAAACAF/p/FJJsJR2GbtoAAAAASUVORK5CYII="},"metadata":{}}],"execution_count":17,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"412c2f7f-a4d5-402b-ac2b-7b51e60e064d"},{"cell_type":"markdown","source":["#### Validate forecasted results and load the model."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"4c7dec16-72b7-447d-802f-dd72da9bc317"},{"cell_type":"code","source":["import numpy as np\n","import pandas as pd\n","import statsmodels.api as sm\n","import matplotlib.pyplot as plt\n","from sklearn.metrics import mean_absolute_error, mean_squared_error"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":4,"statement_ids":[4],"state":"finished","livy_statement_state":"available","session_id":"6fce11ce-2088-4da8-9a6d-87a0f8d9111b","normalized_state":"finished","queued_time":"2024-11-03T01:16:23.1937245Z","session_start_time":null,"execution_start_time":"2024-11-03T01:16:23.6174133Z","execution_finish_time":"2024-11-03T01:16:46.3815426Z","parent_msg_id":"fe34ebe0-9b2e-477b-89fa-3e2fa56f8b9d"},"text/plain":"StatementMeta(, 6fce11ce-2088-4da8-9a6d-87a0f8d9111b, 4, Finished, Available, Finished)"},"metadata":{}}],"execution_count":3,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"a4ab0d70-711b-4bdf-8013-53409b894aad"},{"cell_type":"code","source":["# Get the maximum date from the index\n","max_date = simulated_sales_df.index.max()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":21,"statement_ids":[21],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:12:14.7557645Z","session_start_time":null,"execution_start_time":"2024-11-02T23:12:15.1793216Z","execution_finish_time":"2024-11-02T23:12:15.5263214Z","parent_msg_id":"1055fe66-adc8-40bb-a161-caff66b687f8"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 21, Finished, Available, Finished)"},"metadata":{}}],"execution_count":19,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"f95f7b6f-9c14-43fd-a590-cf02471b0705"},{"cell_type":"code","source":["import pandas as pd\n","from statsmodels.tsa.statespace.sarimax import SARIMAX\n","\n","# Sample data creation (replace this with your actual DataFrame)\n","date_range = pd.date_range(start='2022-01-01', end='2024-12-01', freq='M')\n","sales_data = pd.DataFrame({'sales': range(len(date_range))}, index=date_range)\n","\n","# Define training and validation periods\n","train_end = '2023-12-31' # Last date for training (end of December)\n","validation_start = pd.Timestamp('2024-01-31') # Start of validation period (end of January)\n","validation_end = pd.Timestamp('2024-06-30') # End of validation period (end of June)\n","\n","# Ensure the index is a DatetimeIndex\n","if not isinstance(sales_data.index, pd.DatetimeIndex):\n"," print(\"The index is not a DatetimeIndex.\")\n","else:\n"," print(\"The index is a DatetimeIndex.\")\n","\n","# Fit the model (adjust the order parameters as needed)\n","model = SARIMAX(sales_data['sales'], order=(1, 1, 1), seasonal_order=(1, 1, 1, 12))\n","results = model.fit(disp=False)\n","\n","# Check the fitted model\n","print(results.summary())\n","\n","# Get predictions for the validation period\n","try:\n"," print(\"\\nPASS\\n\")\n"," predictions = results.get_prediction(start=validation_start, end=validation_end, dynamic=False)\n"," predicted_values = predictions.predicted_mean\n"," print(\"Predicted Values:\")\n"," print(predicted_values)\n","except KeyError as e:\n"," print(f\"KeyError: {e}\")\n"," print(f\"Available index in the model: {sales_data.index}\")"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":22,"statement_ids":[22],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:12:24.7295456Z","session_start_time":null,"execution_start_time":"2024-11-02T23:12:25.240496Z","execution_finish_time":"2024-11-02T23:12:26.2918542Z","parent_msg_id":"490e57df-a45f-46be-b1b2-dc0f49b620b7"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 22, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["The index is a DatetimeIndex.\n SARIMAX Results \n==========================================================================================\nDep. Variable: sales No. Observations: 35\nModel: SARIMAX(1, 1, 1)x(1, 1, 1, 12) Log Likelihood 230.177\nDate: Sat, 02 Nov 2024 AIC -450.354\nTime: 23:12:25 BIC -444.899\nSample: 01-31-2022 HQIC -449.069\n - 11-30-2024 \nCovariance Type: opg \n==============================================================================\n coef std err z P>|z| [0.025 0.975]\n------------------------------------------------------------------------------\nar.L1 3.758e-06 1.87e-18 2e+12 0.000 3.76e-06 3.76e-06\nma.L1 -4.708e-10 1.87e-18 -2.51e+08 0.000 -4.71e-10 -4.71e-10\nar.S.L12 7.682e-14 3.52e-35 2.18e+21 0.000 7.68e-14 7.68e-14\nma.S.L12 -7.682e-14 2.92e-35 -2.63e+21 0.000 -7.68e-14 -7.68e-14\nsigma2 1.605e-11 4.92e-10 0.033 0.974 -9.48e-10 9.8e-10\n===================================================================================\nLjung-Box (L1) (Q): nan Jarque-Bera (JB): nan\nProb(Q): nan Prob(JB): nan\nHeteroskedasticity (H): nan Skew: nan\nProb(H) (two-sided): nan Kurtosis: nan\n===================================================================================\n\nWarnings:\n[1] Covariance matrix calculated using the outer product of gradients (complex-step).\n[2] Covariance matrix is singular or near-singular, with condition number inf. Standard errors may be unstable.\n\nPASS\n\nPredicted Values:\n2024-01-31 24.0\n2024-02-29 25.0\n2024-03-31 26.0\n2024-04-30 27.0\n2024-05-31 28.0\n2024-06-30 29.0\nFreq: M, Name: predicted_mean, dtype: float64\n"]},{"output_type":"stream","name":"stderr","text":["/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals\n warnings.warn(\"Maximum Likelihood optimization failed to \"\n"]}],"execution_count":20,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e08c035b-2a37-4793-95b1-dc7bcf039fda"},{"cell_type":"code","source":["# Log the model and parameters\n","model_name = f\"{EXPERIMENT_NAME}-Sarimax\"\n","with mlflow.start_run(run_name=\"Sarimax\") as run:\n"," mlflow.statsmodels.log_model(results,model_name,registered_model_name=model_name)\n"," mlflow.log_params({\"order\":(0,1,1),\"seasonal_order\":(0, 1, 1, 12),'enforce_stationarity':False,'enforce_invertibility':False})\n"," model_uri = f\"runs:/{run.info.run_id}/{model_name}\"\n"," print(\"Model saved in run %s\" % run.info.run_id)\n"," print(f\"Model URI: {model_uri}\")\n","mlflow.end_run()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":23,"statement_ids":[23],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:12:31.4621724Z","session_start_time":null,"execution_start_time":"2024-11-02T23:12:32.0087068Z","execution_finish_time":"2024-11-02T23:12:52.5566216Z","parent_msg_id":"7e7962c1-3919-435b-8aea-c83bc663f222"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 23, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stderr","text":["2024-11-02:23:12:44,932 ERROR [shared_platform_utils.py:82] Create MLModel failed, status_code: 400, b'{\"requestId\":\"5065c1a6-0977-4fcd-a530-83c6ac92c01d\",\"errorCode\":\"ItemDisplayNameAlreadyInUse\",\"message\":\"Requested \\'orders-sales-forecast-Sarimax\\' is already in use\"}'\nRegistered model 'orders-sales-forecast-Sarimax' already exists. Creating a new version of this model...\n2024/11/02 23:12:49 INFO mlflow.store.model_registry.abstract_store: Waiting up to 300 seconds for model version to finish creation. Model name: orders-sales-forecast-Sarimax, version 5\nCreated version '5' of model 'orders-sales-forecast-Sarimax'.\n"]},{"output_type":"stream","name":"stdout","text":["Model saved in run 9afe4db1-5c3b-475a-96cd-1dca63a255ff\nModel URI: runs:/9afe4db1-5c3b-475a-96cd-1dca63a255ff/orders-sales-forecast-Sarimax\n"]},{"output_type":"display_data","data":{"application/vnd.mlflow.run-widget+json":{"info":{"artifact_uri":"sds://onelakemsit.pbidedicated.windows.net/3f4eeb28-7210-44e7-bd10-efcda197a9f7/9a6fa9c6-d583-4646-90be-948000a94098/9afe4db1-5c3b-475a-96cd-1dca63a255ff/artifacts","end_time":1730589170,"experiment_id":"6e249cc0-0384-4a0a-8c72-bad492a83d86","lifecycle_stage":"active","run_id":"9afe4db1-5c3b-475a-96cd-1dca63a255ff","run_name":"","run_uuid":"9afe4db1-5c3b-475a-96cd-1dca63a255ff","start_time":1730589152,"status":"FINISHED","user_id":"e83b0ff5-f802-4776-bae4-11fe73ba932a"},"data":{"metrics":{},"params":{"order":"(0, 1, 1)","seasonal_order":"(0, 1, 1, 12)","enforce_stationarity":"False","enforce_invertibility":"False"},"tags":{"mlflow.user":"1b884fa3-ac7e-44f0-a171-1f215a13ecd4","synapseml.notebook.artifactId":"4ef083b9-cbcc-4f39-a126-7c3611447a5d","synapseml.user.name":"Vindhya Banda","synapseml.user.id":"d7eaa3fc-8cbd-4cef-bc38-50830ac05ed0","synapseml.livy.id":"69bf9935-062b-4346-914c-f3056e2ebcc2","mlflow.runName":"Sarimax","synapseml.run.artifactJobId":"7f403eb5-f92c-4da7-b0ef-ebd8df4b1b59","mlflow.rootRunId":"9afe4db1-5c3b-475a-96cd-1dca63a255ff","synapseml.experimentName":"orders-sales-forecast","synapseml.experiment.artifactId":"9a6fa9c6-d583-4646-90be-948000a94098"}},"inputs":{"dataset_inputs":[]}}},"metadata":{}}],"execution_count":21,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"7f16653c-6f45-4993-85be-3a6179bb3401"},{"cell_type":"code","source":["# Load the saved model\n","loaded_model = mlflow.statsmodels.load_model(model_uri)"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":24,"statement_ids":[24],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:12:55.4569138Z","session_start_time":null,"execution_start_time":"2024-11-02T23:12:55.9034108Z","execution_finish_time":"2024-11-02T23:12:58.9442392Z","parent_msg_id":"a38ab591-3bb5-4746-abda-a6a64b11855f"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 24, Finished, Available, Finished)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"Downloading artifacts: 0%| | 0/9 [00:00 0:\n"," # Calculate the Mean Absolute Percentage Error (MAPE)\n"," mape = mean_absolute_percentage_error(valid_rows['Actual_Sales_x'], valid_rows['Forecasted_Sales']) * 100\n","\n"," # Assign MAPE back to final_data or create a new column\n"," final_data['MAPE'] = np.nan # Initialize MAPE column with NaN\n"," final_data.loc[valid_rows.index, 'MAPE'] = mape # Assign calculated MAPE to valid rows\n","else:\n"," print(\"No valid data available for MAPE calculation.\")\n"," final_data['MAPE'] = np.nan # Ensure MAPE column remains NaN where no valid data exists\n"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":31,"statement_ids":[31],"state":"finished","livy_statement_state":"available","session_id":"69bf9935-062b-4346-914c-f3056e2ebcc2","normalized_state":"finished","queued_time":"2024-11-02T23:14:37.0981562Z","session_start_time":null,"execution_start_time":"2024-11-02T23:14:37.5513296Z","execution_finish_time":"2024-11-02T23:14:37.9412798Z","parent_msg_id":"b699fea2-f925-4e1f-bd13-2ded61198aea"},"text/plain":"StatementMeta(, 69bf9935-062b-4346-914c-f3056e2ebcc2, 31, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["Number of valid rows for MAPE calculation: 0\nNo valid data available for MAPE calculation.\n"]}],"execution_count":28,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"0a5eed96-a4b9-49c5-83d2-09eab6134195"},{"cell_type":"markdown","source":["## Case 2: Forecasting sales for a specific product in a particular region."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"749733a2-61f1-41c4-9f9d-3de44bd5e6b8"},{"cell_type":"markdown","source":["Forecasting the sales of eggs in the Chicago. We have the daily sales data for Eggs in Chicago, with each date showing the total sales amount in dollars. Some dates may show zero sales, which could indicate days with no orders for Eggs."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e4f86c82-5647-4c95-9fa6-8015ed03ec07"},{"cell_type":"markdown","source":["### Import required libraries"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"009a32a6-7576-40f2-b9d9-c5a1d85f2e06"},{"cell_type":"code","source":["import pandas as pd\n","import json\n","from prophet import Prophet\n","import warnings\n","import itertools\n","import numpy as np\n","import matplotlib.pyplot as plt\n","warnings.filterwarnings(\"ignore\")\n","plt.style.use('fivethirtyeight')\n","import pandas as pd\n","import statsmodels.api as sm\n","import matplotlib\n","matplotlib.rcParams['axes.labelsize'] = 14\n","matplotlib.rcParams['xtick.labelsize'] = 12\n","matplotlib.rcParams['ytick.labelsize'] = 12\n","matplotlib.rcParams['text.color'] = 'k'\n","from sklearn.metrics import mean_absolute_percentage_error\n","from datetime import timedelta"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":4,"statement_ids":[4],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:19:58.4648686Z","session_start_time":null,"execution_start_time":"2024-11-05T03:19:59.0539178Z","execution_finish_time":"2024-11-05T03:20:15.3592152Z","parent_msg_id":"1ae553f7-0c03-47e5-956d-0c4a45da2509"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 4, Finished, Available, Finished)"},"metadata":{}}],"execution_count":2,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"10de6dbf-47e6-415d-93b4-5cdb5b1440e2"},{"cell_type":"markdown","source":["### Load the data"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"d8c94611-3236-40d5-8450-176e557f3537"},{"cell_type":"code","source":["# Read from Kusto\n","ordersQuery = \"['orders'] | mv-expand li = parse_json(line_items) | project order_date, store_id, order_id, product_id = toint(li.product_id), quantity = toint(li.quantity), price = toreal(li.price), item_total = toreal(li.item_total), order_total\"\n","inventoryQuery = \"['inventory'] | project date_time, store_id, product_id, in_stock, retail_price\"\n","productsQuery = \"['products'] | project product_id, name, category, photo_path, price_range, stock\"\n","\n","kustoUri = \"https://trd-g8jnmstet4k7q79z9v.z1.kusto.fabric.microsoft.com\"\n","database = \"contosohypermarket\"\n","accessToken = mssparkutils.credentials.getToken(kustoUri)\n","\n","orders_df = spark.read\\\n"," .format(\"com.microsoft.kusto.spark.synapse.datasource\")\\\n"," .option(\"accessToken\", accessToken)\\\n"," .option(\"kustoCluster\", kustoUri)\\\n"," .option(\"kustoDatabase\", database)\\\n"," .option(\"kustoQuery\", ordersQuery).load()\n","\n","inventory_df = spark.read\\\n"," .format(\"com.microsoft.kusto.spark.synapse.datasource\")\\\n"," .option(\"accessToken\", accessToken)\\\n"," .option(\"kustoCluster\", kustoUri)\\\n"," .option(\"kustoDatabase\", database)\\\n"," .option(\"kustoQuery\", inventoryQuery).load()\n","\n","products_df = spark.read\\\n"," .format(\"com.microsoft.kusto.spark.synapse.datasource\")\\\n"," .option(\"accessToken\", accessToken)\\\n"," .option(\"kustoCluster\", kustoUri)\\\n"," .option(\"kustoDatabase\", database)\\\n"," .option(\"kustoQuery\", productsQuery).load()\n","\n","# Convert Spark DataFrames to Pandas DataFrames\n","orders_df = orders_df.toPandas()\n","products_df = products_df.toPandas()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":5,"statement_ids":[5],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:20:18.0228977Z","session_start_time":null,"execution_start_time":"2024-11-05T03:20:18.4875288Z","execution_finish_time":"2024-11-05T03:20:45.9496343Z","parent_msg_id":"bee9a4cd-0829-447f-a25f-46c365a1c73e"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 5, Finished, Available, Finished)"},"metadata":{}}],"execution_count":3,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"48b39ec1-4daf-4756-b6da-95e5c1b6ef5a"},{"cell_type":"markdown","source":["### Data Preprocessing"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"007f637a-5e3c-4ece-84d2-5162990100e8"},{"cell_type":"code","source":["# Filter the inventory for the Chicago region and convert to Pandas DataFrame\n","chicago_inventory = inventory_df[inventory_df['store_id'] == 'CHI'].toPandas()\n","\n","# Merge inventory with products to get product names\n","chicago_inventory_with_names = pd.merge(chicago_inventory, products_df[['product_id', 'name']], on='product_id')\n","\n","# Find the product with the maximum stock\n","max_stock_product = chicago_inventory_with_names.loc[chicago_inventory_with_names['in_stock'].idxmax()]\n","\n","# Display the product name and stock quantity\n","print(\"Product with the highest stock in Chicago:\")\n","print(f\"Product: {max_stock_product['name']}, Stock: {max_stock_product['in_stock']}\")"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":6,"statement_ids":[6],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:20:49.3226112Z","session_start_time":null,"execution_start_time":"2024-11-05T03:20:49.878258Z","execution_finish_time":"2024-11-05T03:20:57.0553621Z","parent_msg_id":"ca0e9f45-5fe3-49d2-8ab4-2569182171c9"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 6, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["Product with the highest stock in Chicago:\nProduct: Strawberry, Stock: 10000\n"]}],"execution_count":4,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"bd96b363-5b96-45f6-b946-b3adc0cff117"},{"cell_type":"code","source":["# Check column names\n","print(\"Orders DataFrame columns:\", orders_df.columns)\n","print(\"Products DataFrame columns:\", products_df.columns)\n","\n","# Merge orders with products to get product details\n","merged_df = pd.merge(orders_df, products_df, on='product_id')\n","\n","# Check merged DataFrame columns\n","print(\"Merged DataFrame columns:\", merged_df.columns)\n","\n","# Filter data for Eggs in Chicago\n","product_name = 'Strawberry'\n","region = 'CHI'\n","filtered_df = merged_df[(merged_df['name'] == product_name) & (merged_df['store_id'] == region)]\n","\n","# Check if filtered_df is empty\n","if filtered_df.empty:\n"," raise ValueError(f\"No data found for product '{product_name}' in region '{region}'.\")"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":7,"statement_ids":[7],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:20:59.9397675Z","session_start_time":null,"execution_start_time":"2024-11-05T03:21:00.3349123Z","execution_finish_time":"2024-11-05T03:21:00.7159952Z","parent_msg_id":"051aa189-200a-4e53-8b37-6ba3906cb428"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 7, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["Orders DataFrame columns: Index(['order_date', 'store_id', 'order_id', 'product_id', 'quantity', 'price',\n 'item_total', 'order_total'],\n dtype='object')\nProducts DataFrame columns: Index(['product_id', 'name', 'category', 'photo_path', 'price_range', 'stock'], dtype='object')\nMerged DataFrame columns: Index(['order_date', 'store_id', 'order_id', 'product_id', 'quantity', 'price',\n 'item_total', 'order_total', 'name', 'category', 'photo_path',\n 'price_range', 'stock'],\n dtype='object')\n"]}],"execution_count":5,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"c0aef7db-4f2b-4a8a-9fa8-e87886f3988e"},{"cell_type":"markdown","source":["### Sales Forecasting"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"265401a2-2ff9-4384-a0ca-217b04fd6f63"},{"cell_type":"code","source":["# Prepare data for Prophet\n","sales_data = filtered_df.groupby('order_date').agg({'quantity': 'sum'}).reset_index()\n","sales_data.columns = ['ds', 'y']\n","\n","# Check the sales_data DataFrame\n","print(sales_data.head())\n","print(sales_data.info())\n","\n","# Handle missing values\n","sales_data = sales_data.dropna()\n","\n","# Ensure there are at least 2 non-NaN rows\n","if sales_data.shape[0] < 2:\n"," raise ValueError('Insufficient data for forecasting. Please ensure there are at least 2 non-NaN rows.')\n","\n","# Fit the model\n","model = Prophet()\n","model.fit(sales_data)\n","\n","# Make future predictions\n","future = model.make_future_dataframe(periods=30) # Forecast for the next 30 days\n","forecast = model.predict(future)"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":8,"statement_ids":[8],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:21:05.2381158Z","session_start_time":null,"execution_start_time":"2024-11-05T03:21:05.6450507Z","execution_finish_time":"2024-11-05T03:21:06.6439494Z","parent_msg_id":"2923ae4a-d877-4037-aff8-fa3938a0bad5"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 8, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":[" ds y\n0 2024-09-26 13:21:01.705 4\n1 2024-09-26 13:22:01.964 8\n2 2024-09-26 13:23:02.225 2\n3 2024-09-26 13:25:02.748 5\n4 2024-09-26 13:27:03.110 5\n\nRangeIndex: 777 entries, 0 to 776\nData columns (total 2 columns):\n # Column Non-Null Count Dtype \n--- ------ -------------- ----- \n 0 ds 777 non-null datetime64[us]\n 1 y 777 non-null int32 \ndtypes: datetime64[us](1), int32(1)\nmemory usage: 9.2 KB\nNone\nDisabling yearly seasonality. Run prophet with yearly_seasonality=True to override this.\ninput tempfile: /tmp/tmpcnr8w6eh/35f5m6b4.json\ninput tempfile: /tmp/tmpcnr8w6eh/jneh1p9t.json\nidx 0\nrunning CmdStan, num_threads: None\nCmdStan args: ['/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/prophet/stan_model/prophet_model.bin', 'random', 'seed=91172', 'data', 'file=/tmp/tmpcnr8w6eh/35f5m6b4.json', 'init=/tmp/tmpcnr8w6eh/jneh1p9t.json', 'output', 'file=/tmp/tmpcnr8w6eh/prophet_modellra6azuw/prophet_model-20241105032105.csv', 'method=optimize', 'algorithm=lbfgs', 'iter=10000']\nChain [1] start processing\nChain [1] done processing\n"]},{"output_type":"stream","name":"stderr","text":["03:21:05 - cmdstanpy - INFO - Chain [1] start processing\n03:21:06 - cmdstanpy - INFO - Chain [1] done processing\n"]}],"execution_count":6,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"b9ff1f2f-69ed-44e7-9ef1-0a66acbb257e"},{"cell_type":"code","source":["# Filter orders for 'Strawberry' in Chicago ('CHI')\n","product_name = 'Strawberry'\n","product_id = products_df[products_df['name'] == product_name].iloc[0]['product_id']\n","filtered_sales_df = orders_df[\n"," (orders_df['product_id'] == product_id) & \n"," (orders_df['store_id'] == 'CHI')\n","]\n","\n","# Aggregate daily sales for the specific product and store\n","actual_sales = filtered_sales_df.groupby('order_date')['quantity'].sum().reset_index()\n","actual_sales.rename(columns={'order_date': 'ds', 'quantity': 'y'}, inplace=True)\n","actual_sales['ds'] = pd.to_datetime(actual_sales['ds'])\n","\n","# Fill in missing dates with zero sales to create a continuous time series\n","date_range = pd.date_range(start=actual_sales['ds'].min(), end=actual_sales['ds'].max(), freq='D')\n","actual_sales = actual_sales.set_index('ds').reindex(date_range, fill_value=0).rename_axis('ds').reset_index()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":9,"statement_ids":[9],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:21:10.347817Z","session_start_time":null,"execution_start_time":"2024-11-05T03:21:10.8112399Z","execution_finish_time":"2024-11-05T03:21:11.1673416Z","parent_msg_id":"d43d268a-df8d-48cf-93ce-591bf18cde66"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 9, Finished, Available, Finished)"},"metadata":{}}],"execution_count":7,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"da702183-cfbc-4251-8509-7f775328135a"},{"cell_type":"markdown","source":["### Plot forecasted data"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"5eaccb9b-a8af-4304-bed6-675dca98be9c"},{"cell_type":"code","source":["# Plot the forecasted data\n","fig = model.plot(forecast)\n","plt.title('Sales Forecast')\n","plt.xlabel('Date')\n","plt.ylabel('Sales Quantity')\n","plt.show()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":10,"statement_ids":[10],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:21:14.0267751Z","session_start_time":null,"execution_start_time":"2024-11-05T03:21:14.4240392Z","execution_finish_time":"2024-11-05T03:21:15.4680752Z","parent_msg_id":"fd19c285-b769-418f-b931-b86049925b12"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 10, Finished, Available, Finished)"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":"
","image/png":"iVBORw0KGgoAAAANSUhEUgAAA9IAAAJgCAYAAABm5lsUAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAADdjElEQVR4nOzdeXwU5eE/8M/M7JXdzX0nQCAcIqcIeFa5FP164VXPimJBrfanULVSQZTWq60UWq1txRbF9qui9ap+tZ6gtioocotCQgLkvpO953h+f4REQu5kk51NPu/XKy/I7Mzsk3022fnMc0lCCAEiIiIiIiIi6hI50gUgIiIiIiIiiiYM0kRERERERETdwCBNRERERERE1A0M0kRERERERETdwCBNRERERERE1A0M0kRERERERETdwCBNRERERERE1A0M0kRERERERETdwCBNRERERERE1A0M0kRERB244YYbIEkShg8fHumiEBERkUkwSBMRkWn5fD48/fTTuOCCCzB06FDExMTA5XJh+PDhOOmkk3DjjTfi2WefRUFBQaSLamqSJHX5a+bMmZEuLhERkelZIl0AIiKitnzxxRe46qqr2gzJhYWFKCwsxJYtW7Bu3ToAgN/vh8Ph6OdSEoXX8OHDUVhYiOuvvx7PPPNMpItDRETtYJAmIiLT2bdvH+bOnYv6+noAwPnnn48f/vCHOO644+BwOFBdXY0dO3Zg48aNePfdd+H3+yNc4ugwbdq05hsP7XG5XP1UGiIioujFIE1ERKazbNmy5hD99NNP48c//nGrfWbPno3Fixejvr4ezzzzDBRF6e9iRh2Xy4UJEyZEuhhERERRj0GaiIhMRdd1vPnmmwAaW1DbCtFHi4uLw+23394fRSMiIiICwMnGiIjIZCoqKpq7ao8cObJX5zIMAx9++CHuuusunH766UhJSYHVakVCQgJOOOEE3HXXXTh48GA4io1AIIAnnngCZ511FjIyMmCz2ZCamopZs2bhiSeeQDAY7PD4r7/+GosWLcLYsWPhdrtht9uRnZ2NKVOmYOHChdiwYUOn5+hLn3/+OW644Qbk5ubC6XQiLi4OEyZMwM9+9rMOX8OCgoLmicyaxvy+9tpruPDCC5GdnQ2LxYITTjih1XElJSVYvnw5pk2bhqSkpObX49JLL8Ubb7zRpTL7fD784Q9/wNy5c5GVlQW73Y709HRMnToVt99+Oz799FMIIdr8WZcvX46ZM2c212VcXBzGjRuHn/zkJ9izZ0+nz71//34sXrwYkyZNQmxsLGw2GzIzMzFp0iRce+21WL9+PRoaGpr3nzlzJiRJQmFhIQDg2Wef5URwRERmJoiIiEykurpaABAAxKRJk3p1rvvvv7/5XO19OZ1O8corr7R7juuvv14AEDk5Oe3u89VXX4lhw4Z1+Dxjx44V+/fvb/P43//+90KW5U7L+s033/TodWg6fsaMGd0+1jAMsXjx4g7L5XA4xHPPPdfm8QcOHGje729/+5u44YYbWh0/efLkFsc888wzwul0dvic8+bNEx6Pp91yb9q0SWRkZHT6mh44cKDFcevWrev0GEVRxB//+Md2n/vll18Wdru90/O8/fbbzcfMmDGj0/17Un9ERNQ32LWbiIhMJTExEcOHD0dBQQF27NiBhx9+GEuXLoUsd78TlaZpyMzMxCWXXIJTTz0Vubm5cDgcOHToEP773//iySefhMfjwTXXXIOtW7fi+OOP7/Zz7NmzBzNmzIDH44HL5cJPfvITnHrqqRg2bBjq6+vxzjvv4IknnsDevXtx7rnn4ssvv0R8fHzz8Tt27MCSJUtgGAaGDx+O2267DVOmTEFycjK8Xi/27duHTZs24fXXX+922cJh2bJlWLNmDQBgyJAhWLp0KaZPn45gMIh3330Xq1atgt/vx/z585GYmIjzzz+/3XOtWbMGO3bswGmnnYZbb70Vxx13HBoaGrB3797mfZ599lnccMMNAIChQ4fi//2//4fx48cjIyMDRUVF+N///V+88MILeP3117FgwQJs2LCh1fP85z//wVlnnQVVVSHLMq666ipceumlGD58OFRVxXfffYd3330Xr732WqtjNU1DYmIiLrroIsyYMQOjR4+Gy+VCcXExtm7dij/84Q+orKzET3/6U4wdOxazZ89ucXxZWRmuv/56BINBpKam4tZbb8Vpp52G1NRUBAIB5Ofn4z//+U+r5163bh28Xi/OOeccFBcXY968eXjwwQdb7MOJ4IiITCTSSZ6IiOhYq1evbtESN2zYMPHTn/5U/O///q/Yt2+fMAyjS+c5cOCACIVC7T5+6NAhkZ2dLQCIH/3oR23u01GLtGEYYvLkyQKAGD9+vCgpKWnzHFu2bGluYV2+fHmLx+677z4BQLhcrnaPF0IIr9cr/H5/u493pOl1nDZtmti5c2e7X99++22L43bt2tXcUj569GhRUVHR6tybN29u/tkyMzNFIBBo8fjRLdIAxDXXXCN0XW+znIcOHWo+19VXXy2CwWCb+z355JPN53v//fdbPBYIBMTQoUMFAGG328W///3vdl+XyspK4fP5Wmw7fPiw8Hq97R5TW1srJk2aJACIH/zgB60e/+tf/9pcth07drR7nlAoJOrr61ttz8nJEQDE9ddf3+6xREQUeQzSRERkOoZhiJtuuqndLq4pKSni0ksvFS+++KJQVbVXz7VmzRoBQMTFxbUZ0DsK0m+++WZzmTZv3tzh89x9990CgMjKymqxfdGiRQKAmDJlSq9+jo609zoe+3Xsz3jrrbc2P/bhhx+2e/5f/vKXzfv9/e9/b/HY0UE6Pj5e1NXVtXueu+66SwAQqampHYZZIYSYPn16czA/2tq1a5uf79FHH+3wHD312muvNT9HZWVli8ceeughAUAkJib26NwM0kRE0YGTjRERkelIkoS//OUv+OCDD3DBBRfAarW2eLyyshKvvPIKrrzySkycOBFff/11l85bX1+PAwcOYPfu3di1axd27doFp9PZ4rHuaOqem5OTg+nTp3e475lnngkAKC4ubjE5V1ZWFoDGLuKbN2/u1vP3tffeew8AkJubi1mzZrW736JFi1od05YLL7wQcXFx7T7e9Hqed955zfXSnqbX87PPPmuxvWnGd7vdjp/85CcdnqMrvF4vCgoKWrxnjn4/bt++vcX+TfVZU1MTse74RETU9zhGmoiITGv27NmYPXs2PB4PPvvsM2zevBlfffUVPv74Y1RVVQEA9u7dixkzZuCzzz7D+PHjW52joKAAq1atwhtvvNHpDN2VlZXIzc3tcvm+/PJLAEBhYSEkSerycaWlpRg2bBgA4Oqrr8YjjzyCYDCI008/Heeccw7OO+88/OAHP8CECRN6NDa8PTNmzMDGjRu7tG8wGMS+ffsAAKecckqH+2ZkZDSPa9+5c2e7+02ePLndx+rq6rB//34AjeOkn3322S6Vs7S0tMX3W7dubX6ujkJ7RyorK7Fq1Sq88sor2LdvX5szex+979EuuugiJCYmoqamBpdccglmzJiBCy+8EGeccQamTJkCi4WXXkREAwFbpImIyPTcbjfOPvtsLFu2DK+88gpKS0vxz3/+E0OGDAEANDQ0YPHixa2Oe/vttzF+/Hg88cQTXVrmqmnZra4qLy/v1v5NfD5f8/+PO+44bNiwAcnJydA0DW+99RZuu+02TJ48GSkpKbjiiivwzjvv9Oh5eqOmpqb5/2lpaZ3un5GRAQCorq5ud5/ExMR2H+vpa3lsnVVUVAAAMjMze3S+r776CmPHjsWjjz6K7777rsMQ3dbzJyUl4c0338SwYcMghMDGjRtx55134qSTTkJCQgIuuOACbNiwAYZh9Kh8RERkDrwtSkREUcdiseDSSy/F6NGjMW3aNIRCIXz44Yeorq5GUlISAKCqqgrXXHMNfD4f3G437rrrLpxzzjkYOXIk4uPjYbPZAAAffvgh5syZAwCdhqZj6boOADj55JPx9NNPd/m4ESNGtPh+3rx5mD17Nl566SW88847+OSTT1BaWoqamhq89NJLeOmll3Deeefh5ZdfRkxMTLfKGA5daW3vymunKEq7jzW9lgDw05/+FDfffHPXCteO7vQQaBIKhXDFFVegqqoKVqsV/+///T/MmzcPY8aMQWJiIux2OwAgPz+/eY3ztn7u0047Dd999x1ee+01vPnmm/jkk09QWFgIr9eLt956C2+99RZOOukkvPnmm0hNTe3Vz0lERJHBIE1ERFFr4sSJOPnkk/HJJ5/AMAzk5eU1B+mXXnoJtbW1AIBXX30VZ511Vpvn6KgFtTMpKSkoKytDWVkZJkyY0OPzAEBsbCxuvPFG3HjjjQCAffv24c0338QTTzyB/Px8/N///R+WLVuG3/3ud716nq46uvW4rKys0/2b9ml6/bsrJSWl+f8ej6fHr2dKSgoOHz6M4uLibh/74YcfIj8/HwDw5JNPYuHChW3u15X3jN1ux5VXXokrr7wSAHDo0CG8/fbbePLJJ7F9+3Zs3rwZN998M1555ZVul5OIiCKPXbuJiCiqNU3uBKDFeOLdu3cDaAx27YVo4Ptxzj0xZcoUAI3jsL/77rsen6cto0ePxpIlS/Dll18iPT0dANpcM7mv2O12jB49GgA6nQStrKwMBQUFABpvbvRESkoKhg4dCgB4//33e9z1eerUqQCAbdu2ob6+vlvHNr1nADQH4Lb05D0zdOhQ3HTTTdi8eXPzTYJ//etfrbqG96QlnYiI+h+DNBERRS0hBL766isAjQEkJyen+TFN0wAAgUCg3VDm8/nw3HPP9fj5L7744ub/P/LIIz0+T0cSExNx4oknAmg9sVVfO/vsswEA+/fvx8cff9zufkd3a286pifmzZsHADh8+HCP6+XCCy8E0NhN+8knn+zWsU3vGaBxtu62GIaBtWvX9qhsAGCz2XDGGWc0P19dXV2Lxx0OB4DGyd6IiMi8GKSJiMhUPB4PTjrpJLzxxhstxs225f7772+e6fmMM85o0T24qTXV5/O12ZKr6zoWLlzYoy7ATS655JLm1sVnnnkGf/jDHzrc/8CBA3j++edbbHv11VdbTOx1rOrq6uabBceOre5rt956a3Mr/y233NJmObdu3dp8EyEzMxOXX355j5/v7rvvbh4Dfvvtt+PTTz/tcP9PP/0UmzZtarHtRz/6UfMkdCtXrsS7777b7vFVVVUtWoSb3jNAY3225Re/+EXzzOBteeeddzp8TwUCAXzyyScAGrvzH/2eBb6fJC0vL6/dcxARUeRxjDQREZnOli1bMG/ePGRmZmLevHk49dRTMWLECMTFxaGhoQE7duzAc889h88//xxAYzfkVatWtTjHFVdcgXvvvRfBYBALFizA9u3bcdZZZyE+Ph67d+/G448/jq+++gqnn346/vOf//SonLIsY8OGDTj11FNRV1eHO+64A6+++iquu+46jBs3DjabDVVVVdixYwfeeecdfPjhh7jkkktw9dVXN5/j97//Pa699lqcd955mD17No4//ngkJiairq4O27dvxxNPPNE8o/Wtt97aw1e0Z8aPH4977rkHjzzyCL755htMmTIF99xzD6ZNm4ZgMIh3330Xq1atgs/ngyRJWLt2bfOEXD0xbNgwPP300/jRj36E+vp6zJo1C1dffTXmzZuH4cOHwzAMlJSU4KuvvsKrr76KnTt34vHHH8eMGTOaz2G32/GPf/wDc+bMQSAQwP/8z//g6quvxmWXXYacnByoqor9+/fjvffew8svv4xdu3Zh+PDhAIBzzjkHaWlpKC8vx/Lly1FYWIiLL74YKSkp2L9/P9auXYsPPvigw/fMCy+8gIsuughz5szBOeecgwkTJiA5ORlerxd79+7Fn/70J+zatQtA4/rbxy6Hddppp+Gjjz7Cli1b8Oijj+J//ud/4HK5AAAxMTHIzs7u8etLRERhJIiIiEzE7/eLjIwMAaBLX0OGDBEffPBBm+f629/+JmRZbvfYK6+8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on2uWtu3b5+w2+3ixRdfjClIp3q/aJoW/P7RRx9t8wXi+PHjwmKxiJtuuilk+/333y8kSRKfffZZh+fauHGjACD+9re/hWyfOnWqKC4uFqqqxtyutrBfuqZfnE6nuPDCC0OOc7vdwuFwiCuuuKLDc7Ffou8XXdeDj+2bb77pMEhnZGRE/ThOx36Jvl+ifa5UVRXHjx8PO3bdunUCgPjLX/4St3OxX6J/rr7++muhKIq49dZbQ47929/+JgCIp59+Om7nSvV+Of3Y4cOHxxwMYnl/4etY9/VLtO8vfB1Lzn6Jx+tYIiR0andBQUHYNrvdjmHDhuGrr74CAKiqig0bNmDmzJnIysoKHldSUoLJkydj/fr1wW29evWKWE173LhxaGpqQnV1ddi+hx56CNXV1bj//vtjanss7Xr33XfRu3dvVFRUhNzHZZddhsbGRmzatKnD80XzXJ3upptuwtSpUzF9+vRoH1bU50rWfgHQbnW91jZt2oTm5mbccMMNIdtvuOEGCCHw0ksvdXgf69evh91ux9VXXx12H4cOHcL27dtjbldb2C9d0y9GoxEOhyPkOIvFEvzqCPsl+n7pzhUP2C/R90u07y+KoiAvLy/s2HHjxgFAm+9FsZ6L/eIXbb9s27YNmqbhu9/9bsixl112GQDghRdeiMu50qFfYj02kljeX84U+yV60b6/8HUsOfslHq9jiZB060jX1dVh586dGD58OACgqqoKbrcb5eXlYceWl5djz549aG5ubvc+N2/ejPz8/LBf/P/85z+477778OSTT8Jut8fUzlja5fV6YTabw44LbPv4449jOnfA6c9Va7///e/x3nvv4YknnujUfXd0rmTtl1h8+umnAICzzz47ZHtRURF69eoV3N/RfQwdOhQGgyFke+B5ieY+zgT7pe37iLZfFixYgE2bNuEPf/gDampqcPjwYfz0pz9FXV0dbrvttk49BvZLfLjdbhQWFkJRFPTp0we33HJLxA8U0WK/RK+995fTvfXWWwAQ1bHRnIv90rZI/eL1egEg7HOG0WiEJElx+4yRDv0SD7G+7/N1LDXwdSyxuup1rKsZOj6ke82fPx+NjY34xS9+AQA4ceIEACA3Nzfs2NzcXAghUFNTg6Kiooj39/vf/x5btmzBqlWroChKcLuu6/jRj36EGTNmhP31IxqxtGvYsGF44403cPDg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SkoAANdffz0A4O2338acOXOCATo7Ozt4jqqqKkyaNAkulwvf/va3cdVVV+HYsWN44YUX8Nprr+HNN9/E+PHju/mRExERxReDNBERUQ8yceJErF69Gu+//z4AYOjQoTh8+DByc3NDjtu8eTMuvvhi3HfffXjmmWcA+IP0/v378fbbb+P666/HpEmTwu6/srISR44cwWuvvYapU6cGt99zzz0YM2YM5s6di48//rjrHiAREVE34NRuIiKiHqS4uBgAcPz4cQCAw+EIC9GAf+r28OHD8cYbb0R937t27cK///1vzJkzJyREA/7R8Llz5+KTTz7hFG8iIkp5HJEmIiLqQYQQYdu2bNmClStXYvv27Th+/DhUVQ3uM5lMUd/3tm3bAABHjhyJWPBs9+7dwf+PGDEixpYTERElDwZpIiKiHuTw4cMAgPz8fADAunXrcM0118But2PatGno378/bDYbJEnCn/70Jxw4cCDq+66urgYAbNy4ERs3bmzzuMbGxjN4BERERInHIE1ERNSDbNmyBQAwduxYAMDSpUthsViwY8cODBo0KOTY5557Lqb7zsrKAgA8/vjjuOWWW868sUREREmK10gTERH1EF988QX+/ve/w2w2Y/r06QD8VbaHDh0aFqIPHToUtvwVACiKAgDQNC1sX6Aa99atW+PddCIioqTCIE1ERNQDvPPOO5g2bRo8Hg/uvvtuOJ1OAEBJSQn27NmDo0ePBo9tbm7GzTffHHKtdECgMNnXX38dtm/cuHEYP3481qxZg7Vr14bt13Udb7/9drweEhERUcJIIlLVESIiIkop+/fvx4ABA1BWVoYf/OAHAACv14tjx45h+/bt+PTTT6EoCu6++2788pe/hCRJAIAnnngCt956K4qKijBr1iyoqop//vOfEELAbrfjo48+CilQ9p///AcjRoxAcXExfvjDH8LhcMDhcODmm28GAOzbtw+TJ0/GgQMHcO6556KiogIWiwUHDx7E1q1b8c0336C5ubn7nyAiIqI4YpAmIiJKA4Eg3ZrVakV2djaGDBmCCy+8EHPmzEFZWVnIMUIIPP3003j88cdRVVWF7OxsXHrppXjggQcwe/ZsvP3222GVvv/85z9j+fLl+OKLL+DxeFBSUoL9+/cH99fU1ODXv/41XnrpJVRVVUFRFBQVFWHs2LGYNWtWcFo5ERFRqmKQJiIiIiIiIooBr5EmIiIiIiIiigGDNBEREREREVEMGKSJiIiIiIiIYsAgTURERERERBQDBmkiIiIiIiKiGDBIExEREREREcWAQZqIiIiIiIgoBgzSRERERERERDFgkCYiIiIiIiKKAYM0ERERERERUQwYpImIiIiIiIhiwCBNREREREREFAMGaSIiIiIiIqIY/H9w+WMoB2oSGAAAAABJRU5ErkJggg=="},"metadata":{}}],"execution_count":8,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"a0fb27bb-f6f1-4c8a-bb35-35c2d56e3e34"},{"cell_type":"markdown","source":["### Scoring the model for accuracy"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"f48c2e1b-54f6-401a-81d3-3c6cfe2ef4ac"},{"cell_type":"code","source":["import pandas as pd\n","from sklearn.metrics import mean_absolute_error, mean_absolute_percentage_error\n","\n","# Rename actual DataFrame\n","actual = sales_data.rename(columns={'y': 'actual'})\n","\n","# Prepare forecasted DataFrame\n","forecasted = forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].rename(columns={'yhat': 'forecasted', 'yhat_lower': 'forecasted_lower', 'yhat_upper': 'forecasted_upper'})\n","\n","# Convert 'ds' in both DataFrames to datetime\n","actual['ds'] = pd.to_datetime(actual['ds'])\n","forecasted['ds'] = pd.to_datetime(forecasted['ds'])\n","\n","# Standardize to nanoseconds precision\n","actual['ds'] = actual['ds'].dt.floor('ns') # Convert to nanoseconds\n","forecasted['ds'] = forecasted['ds'].dt.floor('ns') # Keep as nanoseconds\n","\n","# Check column names and dtypes\n","print(\"Actual DataFrame columns:\", actual.columns)\n","print(\"Forecasted DataFrame columns:\", forecasted.columns)\n","print(\"Actual ds dtype:\", actual['ds'].dtype)\n","print(\"Forecasted ds dtype:\", forecasted['ds'].dtype)\n","\n","# Merge dataframes on 'ds'\n","merged = actual.merge(forecasted, on='ds', how='inner')\n","\n","# Calculate accuracy metrics\n","mae = mean_absolute_error(merged['actual'], merged['forecasted'])\n","mape = mean_absolute_percentage_error(merged['actual'], merged['forecasted'])\n","\n","print(f'Mean Absolute Error (MAE): {mae}')\n","print(f'Mean Absolute Percentage Error (MAPE): {mape}')"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":11,"statement_ids":[11],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:21:21.2700181Z","session_start_time":null,"execution_start_time":"2024-11-05T03:21:21.6990947Z","execution_finish_time":"2024-11-05T03:21:22.1023814Z","parent_msg_id":"64a298a1-f93d-4608-ae7e-9851e6e1258d"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 11, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["Actual DataFrame columns: Index(['ds', 'actual'], dtype='object')\nForecasted DataFrame columns: Index(['ds', 'forecasted', 'forecasted_lower', 'forecasted_upper'], dtype='object')\nActual ds dtype: datetime64[us]\nForecasted ds dtype: datetime64[ns]\nMean Absolute Error (MAE): 16.135472447036864\nMean Absolute Percentage Error (MAPE): 2.2703632900055903\n"]}],"execution_count":9,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e1418afd-a3c4-455d-816a-e170a3b06891"},{"cell_type":"markdown","source":["### Calculating forecasted data"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"6d5390e8-e8d5-4dfa-919a-68751079dcd8"},{"cell_type":"code","source":["forecast[['ds', 'yhat']].to_csv('forecast.csv', index=False)"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":12,"statement_ids":[12],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:21:30.9470509Z","session_start_time":null,"execution_start_time":"2024-11-05T03:21:31.3580641Z","execution_finish_time":"2024-11-05T03:21:31.7391434Z","parent_msg_id":"8635c807-cc9a-461e-89f3-e752c7f5de22"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 12, Finished, Available, Finished)"},"metadata":{}}],"execution_count":10,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"4bf2e2e3-fc56-485e-a5a4-4234d88dbc93"},{"cell_type":"markdown","source":["##### Preparing actual and forecasted data"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"80a0aaf6-d7bc-44a0-b38b-ee8d0ef97c0f"},{"cell_type":"code","source":["# Filter orders for 'Strawberry' in Chicago ('CHI')\n","product_name = 'Strawberry'\n","product_id = products_df[products_df['name'] == product_name].iloc[0]['product_id']\n","filtered_sales_df = orders_df[\n"," (orders_df['product_id'] == product_id) & \n"," (orders_df['store_id'] == 'CHI')\n","]\n","\n","# Aggregate daily sales for the specific product and store\n","actual_sales = filtered_sales_df.groupby('order_date')['quantity'].sum().reset_index()\n","actual_sales.rename(columns={'order_date': 'ds', 'quantity': 'y'}, inplace=True)\n","actual_sales['ds'] = pd.to_datetime(actual_sales['ds'])\n","\n","# Fill in missing dates with zero sales to create a continuous time series\n","date_range = pd.date_range(start=actual_sales['ds'].min(), end=actual_sales['ds'].max(), freq='D')\n","actual_sales = actual_sales.set_index('ds').reindex(date_range, fill_value=0).rename_axis('ds').reset_index()"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":13,"statement_ids":[13],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:21:35.8897096Z","session_start_time":null,"execution_start_time":"2024-11-05T03:21:36.3128878Z","execution_finish_time":"2024-11-05T03:21:36.661125Z","parent_msg_id":"4b745b13-20e5-4e47-8e93-51b2dc16237c"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 13, Finished, Available, Finished)"},"metadata":{}}],"execution_count":11,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"43571449-9160-4f0a-b4f0-a2dbde8418c5"},{"cell_type":"code","source":["# Initialize and fit Prophet model\n","model = Prophet()\n","model.fit(actual_sales)\n","\n","# Forecast the next 30 days\n","future = model.make_future_dataframe(periods=30)\n","forecast = model.predict(future)"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":14,"statement_ids":[14],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:21:41.1291977Z","session_start_time":null,"execution_start_time":"2024-11-05T03:21:41.5068476Z","execution_finish_time":"2024-11-05T03:21:41.8766493Z","parent_msg_id":"ac1e7f28-ba1c-4c35-83c9-d35ea4d718ce"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 14, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stderr","text":["03:21:41 - cmdstanpy - INFO - Chain [1] start processing\n03:21:41 - cmdstanpy - INFO - Chain [1] done processing\n"]},{"output_type":"stream","name":"stdout","text":["Disabling yearly seasonality. Run prophet with yearly_seasonality=True to override this.\nDisabling daily seasonality. Run prophet with daily_seasonality=True to override this.\nn_changepoints greater than number of observations. Using 19.\ninput tempfile: /tmp/tmpcnr8w6eh/4u6xy9zg.json\ninput tempfile: /tmp/tmpcnr8w6eh/3nr4slau.json\nidx 0\nrunning CmdStan, num_threads: None\nCmdStan args: ['/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/prophet/stan_model/prophet_model.bin', 'random', 'seed=53327', 'data', 'file=/tmp/tmpcnr8w6eh/4u6xy9zg.json', 'init=/tmp/tmpcnr8w6eh/3nr4slau.json', 'output', 'file=/tmp/tmpcnr8w6eh/prophet_model9b3p2hun/prophet_model-20241105032141.csv', 'method=optimize', 'algorithm=newton', 'iter=10000']\nChain [1] start processing\nChain [1] done processing\n"]}],"execution_count":12,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"74c17c5a-a4b7-446d-bee3-604e60ac4068"},{"cell_type":"code","source":["# Prepare forecast data for MAPE calculation\n","forecasted_sales = forecast[['ds', 'yhat']].rename(columns={'yhat': 'Forecasted_Sales'})\n","\n","# Merge actual sales with forecasted sales on 'ds' date\n","final_data = actual_sales.merge(forecasted_sales, on='ds', how='left')\n","\n","# Filter to remove rows where 'y' (actual sales) is NaN for valid MAPE calculation\n","valid_data = final_data.dropna(subset=['y'])\n","\n","# Filter out rows where actual sales (y) are zero to avoid division by zero in MAPE calculation\n","valid_data = final_data[final_data['y'] != 0].dropna(subset=['y'])\n","\n","# Calculate MAPE only on valid entries where y is not zero\n","if not valid_data.empty:\n"," valid_data['MAPE'] = mean_absolute_percentage_error(valid_data['y'], valid_data['Forecasted_Sales']) * 100\n","else:\n"," print(\"No valid data available for MAPE calculation (all y values are zero or missing).\")\n","\n","# Display first few rows of valid data with MAPE\n","print(valid_data[['ds', 'y', 'Forecasted_Sales', 'MAPE']].head())"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":15,"statement_ids":[15],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:21:46.1542353Z","session_start_time":null,"execution_start_time":"2024-11-05T03:21:46.601026Z","execution_finish_time":"2024-11-05T03:21:46.9453965Z","parent_msg_id":"3e221c63-10dc-4ab4-9241-25f654d2f946"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 15, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":[" ds y Forecasted_Sales MAPE\n0 2024-09-26 13:21:01.705 4 1.310092 67.247704\n"]}],"execution_count":13,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"c71d537b-e700-4ba2-aca8-0ce95eabdd7a"},{"cell_type":"markdown","source":["##### Simulating data"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"56bb490e-c1ff-4cdf-a25b-4b9f703a17f1"},{"cell_type":"code","source":["# Parameters for synthetic data generation\n","start_date = actual_sales['ds'].min() - timedelta(days=365) # Start one year earlier\n","end_date = actual_sales['ds'].min() - timedelta(days=1) # End right before actual data starts\n","date_range = pd.date_range(start=start_date, end=end_date, freq='D')\n","\n","# Generate seasonal pattern with some random noise\n","np.random.seed(42)\n","seasonal_pattern = 10 + 5 * np.sin(2 * np.pi * date_range.dayofyear / 365) # Yearly seasonality\n","noise = np.random.normal(0, 2, len(date_range)) # Random noise\n","\n","# Create synthetic sales data\n","synthetic_sales = pd.DataFrame({\n"," 'ds': date_range,\n"," 'y': pd.Series(seasonal_pattern + noise).clip(lower=0) # Ensure no negative sales\n","})\n","\n","# Concatenate synthetic sales with actual sales\n","extended_sales = pd.concat([synthetic_sales, actual_sales]).sort_values(by='ds').reset_index(drop=True)"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":16,"statement_ids":[16],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:21:56.7511226Z","session_start_time":null,"execution_start_time":"2024-11-05T03:21:57.1414116Z","execution_finish_time":"2024-11-05T03:21:57.5089829Z","parent_msg_id":"f6e94e07-932c-4250-885a-f3186f9ffa3e"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 16, Finished, Available, Finished)"},"metadata":{}}],"execution_count":14,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"840e1912-413f-459f-a0e3-b0853d8af473"},{"cell_type":"markdown","source":["##### Integrate simulated data with Prophet model"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"409560e9-df84-456d-87b4-0cb314204ed2"},{"cell_type":"code","source":["# Initialize and fit Prophet model with extended sales data\n","model = Prophet()\n","model.fit(extended_sales)\n","\n","# Forecast the next 30 days\n","future = model.make_future_dataframe(periods=30)\n","forecast = model.predict(future)\n","\n","# Prepare forecast data for MAPE calculation\n","forecasted_sales = forecast[['ds', 'yhat']].rename(columns={'yhat': 'Forecasted_Sales'})\n","\n","# Merge actual sales with forecasted sales on 'ds' date\n","final_data = actual_sales.merge(forecasted_sales, on='ds', how='left')\n","\n","# Filter to remove rows where 'y' (actual sales) is NaN for valid MAPE calculation\n","valid_data = final_data.dropna(subset=['y'])\n","\n","# Filter out rows where actual sales (y) are zero to avoid division by zero in MAPE calculation\n","valid_data = final_data[(final_data['y'] != 0) & (~final_data['Forecasted_Sales'].isna())]"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":17,"statement_ids":[17],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:22:12.01668Z","session_start_time":null,"execution_start_time":"2024-11-05T03:22:12.3966452Z","execution_finish_time":"2024-11-05T03:22:12.7834637Z","parent_msg_id":"46438ea9-fe81-4274-9958-793a8e0a3bcf"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 17, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stderr","text":["03:22:12 - cmdstanpy - INFO - Chain [1] start processing\n03:22:12 - cmdstanpy - INFO - Chain [1] done processing\n"]},{"output_type":"stream","name":"stdout","text":["Disabling yearly seasonality. Run prophet with yearly_seasonality=True to override this.\nDisabling daily seasonality. Run prophet with daily_seasonality=True to override this.\ninput tempfile: /tmp/tmpcnr8w6eh/fpytl34j.json\ninput tempfile: /tmp/tmpcnr8w6eh/whzg23sw.json\nidx 0\nrunning CmdStan, num_threads: None\nCmdStan args: ['/home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages/prophet/stan_model/prophet_model.bin', 'random', 'seed=36194', 'data', 'file=/tmp/tmpcnr8w6eh/fpytl34j.json', 'init=/tmp/tmpcnr8w6eh/whzg23sw.json', 'output', 'file=/tmp/tmpcnr8w6eh/prophet_modelfj0kckb0/prophet_model-20241105032212.csv', 'method=optimize', 'algorithm=lbfgs', 'iter=10000']\nChain [1] start processing\nChain [1] done processing\n"]}],"execution_count":15,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"53aea9c4-eddd-4a9a-9a26-5cf7459d1b8f"},{"cell_type":"markdown","source":["##### Calculating MAPE"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"7dafbdb5-bdca-47d4-8cc4-5ce8055c31e8"},{"cell_type":"code","source":["# Check if valid_data is not empty before calculating MAPE\n","if not valid_data.empty:\n"," valid_data['MAPE'] = mean_absolute_percentage_error(valid_data['y'], valid_data['Forecasted_Sales']) * 100\n"," print(valid_data[['ds', 'y', 'Forecasted_Sales', 'MAPE']].head())\n","else:\n"," print(\"No valid data available for MAPE calculation (all y values are zero or missing).\")\n","\n","# Display the first few rows of the final data with MAPE\n","print(valid_data[['ds', 'y', 'Forecasted_Sales', 'MAPE']].head())"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":18,"statement_ids":[18],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:22:15.6725467Z","session_start_time":null,"execution_start_time":"2024-11-05T03:22:16.0734557Z","execution_finish_time":"2024-11-05T03:22:16.4378175Z","parent_msg_id":"20e0e7d2-1098-4eca-8656-b9440ce76bae"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 18, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":[" ds y Forecasted_Sales MAPE\n0 2024-09-26 13:21:01.705 4 3.175803 20.604931\n ds y Forecasted_Sales MAPE\n0 2024-09-26 13:21:01.705 4 3.175803 20.604931\n"]}],"execution_count":16,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e5e5edb1-e546-463a-8f8a-0b2156bbbbfd"},{"cell_type":"markdown","source":["The updated output with a more reasonable MAPE value (around 20.6%) suggests that the adjustments made to filter out rows with zero values in y have worked well. This value is now within a plausible range, indicating that the MAPE calculation is functioning as expected, and the model's forecasts are in a more meaningful comparison with the actual sales data."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"0ed7e66f-77e8-4a20-9dfa-974eff1a3ea7"},{"cell_type":"markdown","source":["#### Recommendations for the future\n","- Experiment with adding yearly_seasonality=True or daily_seasonality=True when initializing the Prophet model to account for potential seasonal effects.\n","- Generating more synthetic data or investigating other external data sources to enrich the training set.\n","- Introducing additional relevant factors, like holidays or product promotions."],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"f08d34f4-5eb8-453a-bbc5-650073288851"},{"cell_type":"markdown","source":["### Visualize in PowerBI"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"cf0da18a-60e7-4717-b707-318ca0b916fa"},{"cell_type":"code","source":["# Prepare future predictions DataFrame\n","future_predictions = forecast[['ds', 'yhat']].rename(columns={'yhat': 'Forecasted_Sales'})\n","future_predictions['Category'] = 'Future'"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":20,"statement_ids":[20],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:35:10.6036639Z","session_start_time":null,"execution_start_time":"2024-11-05T03:35:11.0704068Z","execution_finish_time":"2024-11-05T03:35:11.4887525Z","parent_msg_id":"85069a28-213a-4605-b401-1878623ab781"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 20, Finished, Available, Finished)"},"metadata":{}}],"execution_count":18,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"4065b5ac-2cbe-41ce-8d4e-29e3f6e2a999"},{"cell_type":"code","source":["# Prepare actual sales DataFrame (assuming 'actual_sales' has 'ds' and 'y' columns)\n","actual_predictions = actual_sales.rename(columns={'y': 'Actual_Sales'})\n","actual_predictions['Category'] = 'Actual'"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":21,"statement_ids":[21],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:35:13.3291876Z","session_start_time":null,"execution_start_time":"2024-11-05T03:35:13.794871Z","execution_finish_time":"2024-11-05T03:35:14.285944Z","parent_msg_id":"e50cffe4-ddfd-4808-a05f-286880dc3795"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 21, Finished, Available, Finished)"},"metadata":{}}],"execution_count":19,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"c831bc24-3c25-4cf4-823b-04196cb8b6e1"},{"cell_type":"code","source":["# Merge actual and forecasted DataFrames\n","combined_df = pd.merge(\n"," actual_predictions[['ds', 'Actual_Sales']],\n"," future_predictions[['ds', 'Forecasted_Sales']],\n"," on='ds',\n"," how='outer'\n",")\n","combined_df['Category'] = combined_df.apply(lambda row: 'Actual' if pd.notnull(row['Actual_Sales']) else 'Future', axis=1)"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":22,"statement_ids":[22],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:35:15.8414792Z","session_start_time":null,"execution_start_time":"2024-11-05T03:35:16.331134Z","execution_finish_time":"2024-11-05T03:35:16.7296294Z","parent_msg_id":"4ddee541-6605-4cc9-b258-bee6657445cb"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 22, Finished, Available, Finished)"},"metadata":{}}],"execution_count":20,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"1f0ae9ab-1c30-4eaa-8033-b23a1be0e941"},{"cell_type":"code","source":["from sklearn.metrics import mean_absolute_percentage_error\n","\n","# Filter out rows with null actual sales for MAPE calculation\n","valid_data = combined_df.dropna(subset=['Actual_Sales'])\n","\n","# Calculate MAPE (excluding zero values in 'Actual_Sales')\n","if not valid_data.empty:\n"," mape = mean_absolute_percentage_error(valid_data['Actual_Sales'], valid_data['Forecasted_Sales']) * 100\n"," print(f'MAPE: {mape:.2f}%')\n","else:\n"," print(\"No valid data available for MAPE calculation.\")"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":23,"statement_ids":[23],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:35:18.7566662Z","session_start_time":null,"execution_start_time":"2024-11-05T03:35:19.284397Z","execution_finish_time":"2024-11-05T03:35:19.6311776Z","parent_msg_id":"5a61ed09-40be-468f-a998-52cfdd7db6d8"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 23, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["MAPE: 767881500651486848.00%\n"]}],"execution_count":21,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"3fcb65d0-a075-4e2d-ba95-87b81f2e0a34"},{"cell_type":"code","source":["combined_df['Category'] = combined_df.apply(\n"," lambda row: 'Actual' if pd.notnull(row['Actual_Sales']) else 'Future', axis=1\n",")"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":24,"statement_ids":[24],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:35:21.7573387Z","session_start_time":null,"execution_start_time":"2024-11-05T03:35:22.156576Z","execution_finish_time":"2024-11-05T03:35:22.5354367Z","parent_msg_id":"6c0e4d87-0dc2-476f-ab07-7c16c5d9315b"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 24, Finished, Available, Finished)"},"metadata":{}}],"execution_count":22,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"b970ce06-7a78-4dd0-b956-bba9064a63b4"},{"cell_type":"code","source":["# Filter rows where 'Actual_Sales' is not null\n","filtered_combined_df = combined_df[~combined_df['Actual_Sales'].isnull()]"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":25,"statement_ids":[25],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:35:23.6044887Z","session_start_time":null,"execution_start_time":"2024-11-05T03:35:24.0540518Z","execution_finish_time":"2024-11-05T03:35:24.4330266Z","parent_msg_id":"4f28a7b0-db04-4cbd-ad23-971c355f0316"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 25, Finished, Available, Finished)"},"metadata":{}}],"execution_count":23,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"63468c4e-5b4a-4c64-89d3-d624e4a08ab6"},{"cell_type":"code","source":["# Create the input DataFrame from actual sales\n","input_df = actual_sales.reset_index()\n","input_df.rename(columns={'ds': 'Date', 'y': 'Actual_Sales'}, inplace=True)\n","input_df['Category'] = 'Your Category Name' # Change 'Your Category Name' to your use case\n","input_df['MAPE'] = np.nan\n","input_df['Forecasted_Sales'] = np.nan"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":26,"statement_ids":[26],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:37:05.8374085Z","session_start_time":null,"execution_start_time":"2024-11-05T03:37:06.3426543Z","execution_finish_time":"2024-11-05T03:37:06.7011932Z","parent_msg_id":"9459ff71-c9d8-4cbf-bef3-b366df84581a"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 26, Finished, Available, Finished)"},"metadata":{}}],"execution_count":24,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"edffddb2-6cec-442e-a186-1ab4e77d4dda"},{"cell_type":"code","source":["# Combine actual data with forecast data where 'Actual_Sales' is NaN\n","combined_df = pd.concat([input_df, forecast[['ds', 'yhat']].rename(columns={'ds': 'Date', 'yhat': 'Forecasted_Sales'})])\n","combined_df['Category'].fillna('Forecast', inplace=True)"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":27,"statement_ids":[27],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:37:08.6991979Z","session_start_time":null,"execution_start_time":"2024-11-05T03:37:09.1371946Z","execution_finish_time":"2024-11-05T03:37:09.4783961Z","parent_msg_id":"f52f3fb6-645d-40b9-8ef5-a7ce9f8f55ad"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 27, Finished, Available, Finished)"},"metadata":{}}],"execution_count":25,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"c899ca3b-ab6d-41d2-a346-a2bdc52cb851"},{"cell_type":"code","source":["# Write the final data to Delta Lake table\n","table_name = \"Strawberry_Chicago_Demand_Forecast_Table\"\n","spark.createDataFrame(combined_df).write.mode(\"overwrite\").format(\"delta\").save(f\"Tables/{table_name}\")\n","print(f\"Spark DataFrame saved to Delta table: {table_name}\")"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":28,"statement_ids":[28],"state":"finished","livy_statement_state":"available","session_id":"e37a719e-11cd-4903-b8fe-5b6ec76f2489","normalized_state":"finished","queued_time":"2024-11-05T03:37:11.3435008Z","session_start_time":null,"execution_start_time":"2024-11-05T03:37:11.7588443Z","execution_finish_time":"2024-11-05T03:37:26.4720364Z","parent_msg_id":"82e3e439-d58d-4a23-85b7-f04caf24286e"},"text/plain":"StatementMeta(, e37a719e-11cd-4903-b8fe-5b6ec76f2489, 28, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["Spark DataFrame saved to Delta table: Strawberry_Chicago_Demand_Forecast_Table\n"]}],"execution_count":26,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"350ab0c3-218c-4d16-ae7d-765dc74f9251"}],"metadata":{"kernel_info":{"name":"synapse_pyspark"},"kernelspec":{"name":"synapse_pyspark","language":"Python","display_name":"Synapse PySpark"},"language_info":{"name":"python"},"microsoft":{"language":"python","language_group":"synapse_pyspark","ms_spell_check":{"ms_spell_check_language":"en"}},"widgets":{"application/vnd.jupyter.widget-state+json":{"version_major":2,"version_minor":0,"state":{"5a03f075878b4064ab2f7d8cce157b08":{"model_name":"FloatProgressModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"value":9,"max":9,"bar_style":"success","style":"IPY_MODEL_972cdd559ebf48189e9d445fe3122366","layout":"IPY_MODEL_36fcfa9fac014b779b6dbeb09ab35479"}},"972cdd559ebf48189e9d445fe3122366":{"model_name":"ProgressStyleModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"description_width":""}},"ec44fa797cc54cf99c42dc4ba813aa50":{"model_name":"HTMLStyleModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"description_width":"","font_size":null,"text_color":null}},"427479fe41cf407f8d0122dca3bc36df":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"76c4c8dd7d9847229100d098d6e5388e":{"model_name":"HTMLModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"value":" 9/9 [00:00<00:00, 9.05it/s]","layout":"IPY_MODEL_109021a0d5e9460ebf1b762d0b925f30","style":"IPY_MODEL_ec44fa797cc54cf99c42dc4ba813aa50"}},"18bf4a1c2f914d728bf99d59e54e7946":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"8d87a517fc5e474a9f6a03e1b20247b8":{"model_name":"HBoxModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"children":["IPY_MODEL_1e5e5a7e899d4ee6ac242857469e47e0","IPY_MODEL_5a03f075878b4064ab2f7d8cce157b08","IPY_MODEL_76c4c8dd7d9847229100d098d6e5388e"],"layout":"IPY_MODEL_18bf4a1c2f914d728bf99d59e54e7946"}},"1e5e5a7e899d4ee6ac242857469e47e0":{"model_name":"HTMLModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"value":"Downloading artifacts: 100%","layout":"IPY_MODEL_427479fe41cf407f8d0122dca3bc36df","style":"IPY_MODEL_6b62b69da7c34c34bc0b2134c369f2c2"}},"36fcfa9fac014b779b6dbeb09ab35479":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}},"6b62b69da7c34c34bc0b2134c369f2c2":{"model_name":"HTMLStyleModel","model_module":"@jupyter-widgets/controls","model_module_version":"2.0.0","state":{"description_width":"","font_size":null,"text_color":null}},"109021a0d5e9460ebf1b762d0b925f30":{"model_name":"LayoutModel","model_module":"@jupyter-widgets/base","model_module_version":"2.0.0","state":{}}}}},"nteract":{"version":"nteract-front-end@1.0.0"},"spark_compute":{"compute_id":"/trident/default","session_options":{"conf":{"spark.synapse.nbs.session.timeout":"1200000"}}},"dependencies":{"lakehouse":{"default_lakehouse":"1e009111-e0de-44ad-adaf-9a5240002190","default_lakehouse_name":"SuperstoreForecast","default_lakehouse_workspace_id":"3f4eeb28-7210-44e7-bd10-efcda197a9f7"}}},"nbformat":4,"nbformat_minor":5} \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/fabric/ot_dashboard.json b/azure_jumpstart_ag/artifacts/fabric/ot_dashboard.json new file mode 100644 index 0000000000..46481b507a --- /dev/null +++ b/azure_jumpstart_ag/artifacts/fabric/ot_dashboard.json @@ -0,0 +1,812 @@ +{ + "$schema": "https://msitpbiadx.powerbi.com/static/d/schema/54/dashboard.json", + "id": "4ca6d90b-dda9-444c-a3c9-eb99bde78b66", + "eTag": "\"0d986902e12d44e9b7187e3eb61e2b85\"", + "schema_version": "54", + "title": "OT Dashboard", + "tiles": [ + { + "id": "6c5c8567-04ee-470d-ab31-eee08a9c26ee", + "title": "Refrigerator Status", + "visualType": "multistat", + "pageId": "e813fc9f-4788-43f3-a890-ca213b19d6e9", + "layout": { + "x": 0, + "y": 6, + "width": 3, + "height": 6 + }, + "queryRef": { + "kind": "query", + "queryId": "a499aa12-4369-493d-93ea-409aa7dd483c" + }, + "hideTitle": true, + "visualOptions": { + "multiStat__textSize": "auto", + "multiStat__valueColumn": "door_status", + "colorRulesDisabled": false, + "colorStyle": "light", + "multiStat__displayOrientation": "horizontal", + "multiStat__labelColumn": "device_id_label", + "multiStat__slot": { + "width": 1, + "height": 2 + }, + "colorRules": [ + { + "id": "c807c2d3-43f7-4af9-8a9e-9e756b71e1d8", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "operator": "==", + "column": "door_status", + "values": [ + "Open" + ] + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "red", + "tag": "", + "icon": null, + "ruleName": "Temperature Gauge", + "visualType": "multistat" + }, + { + "id": "85140876-c125-4982-ba46-0e018c1d9aec", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "operator": "==", + "column": "door_status", + "values": [ + "Closed" + ] + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "green", + "tag": "", + "icon": null, + "ruleName": "Sensor Lag", + "visualType": "multistat" + } + ] + } + }, + { + "id": "bbd3ed7e-296d-4784-a2ab-3341f0019572", + "title": "New tile", + "visualType": "multistat", + "pageId": "e813fc9f-4788-43f3-a890-ca213b19d6e9", + "layout": { + "x": 0, + "y": 0, + "width": 3, + "height": 6 + }, + "queryRef": { + "kind": "query", + "queryId": "e872f3db-a364-4f27-9c45-6302e6426a0a" + }, + "hideTitle": true, + "visualOptions": { + "multiStat__textSize": "auto", + "multiStat__valueColumn": "status_label", + "colorRulesDisabled": false, + "colorStyle": "light", + "multiStat__displayOrientation": "horizontal", + "multiStat__labelColumn": "device_id", + "multiStat__slot": { + "width": 1, + "height": 2 + }, + "colorRules": [ + { + "id": "b832c4c4-64a6-41b5-bffa-11d82d15cd3b", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "operator": "==", + "column": "status", + "values": [ + "on" + ] + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "green", + "tag": "", + "icon": null, + "ruleName": "", + "visualType": "multistat" + }, + { + "id": "a4203fa2-9755-4080-b83b-731edced75c8", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "operator": "==", + "column": "status", + "values": [ + "off" + ] + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "red", + "tag": "", + "icon": null, + "ruleName": "", + "visualType": "multistat" + } + ] + } + }, + { + "id": "7d5ce537-2733-4aca-9ca4-292b77384659", + "title": "Brightness Level (Lumens)", + "visualType": "line", + "pageId": "e813fc9f-4788-43f3-a890-ca213b19d6e9", + "layout": { + "x": 3, + "y": 0, + "width": 10, + "height": 6 + }, + "queryRef": { + "kind": "query", + "queryId": "15b59907-6b86-47f5-947c-1d824ad91e38" + }, + "visualOptions": { + "multipleYAxes": { + "base": { + "id": "-1", + "label": "", + "columns": [], + "yAxisMaximumValue": 100, + "yAxisMinimumValue": null, + "yAxisScale": "linear", + "horizontalLines": [] + }, + "additional": [], + "showMultiplePanels": false + }, + "hideLegend": false, + "legendLocation": "bottom", + "xColumnTitle": "", + "xColumn": "timestamp", + "yColumns": [ + "brightness_level" + ], + "seriesColumns": [ + "device_id" + ], + "xAxisScale": "linear", + "verticalLine": "", + "crossFilterDisabled": false, + "drillthroughDisabled": false, + "crossFilter": [], + "drillthrough": [] + } + }, + { + "id": "e8fd7d81-3e06-4485-aef1-ba3c341f6461", + "title": "Lighting Power Utilization (kWh)", + "visualType": "area", + "pageId": "e813fc9f-4788-43f3-a890-ca213b19d6e9", + "layout": { + "x": 13, + "y": 0, + "width": 8, + "height": 6 + }, + "queryRef": { + "kind": "query", + "queryId": "baf31768-a72a-4d2f-9fea-7d546122263a" + }, + "visualOptions": { + "multipleYAxes": { + "base": { + "id": "-1", + "label": "", + "columns": [], + "yAxisMaximumValue": null, + "yAxisMinimumValue": null, + "yAxisScale": "linear", + "horizontalLines": [] + }, + "additional": [], + "showMultiplePanels": true + }, + "hideLegend": true, + "legendLocation": "bottom", + "xColumnTitle": "", + "xColumn": "timestamp", + "yColumns": [ + "power_usage_kwh" + ], + "seriesColumns": [ + "device_id" + ], + "xAxisScale": "linear", + "verticalLine": "", + "crossFilterDisabled": false, + "drillthroughDisabled": false, + "crossFilter": [], + "drillthrough": [] + } + }, + { + "id": "8ba8d51e-4ca9-4ac4-8838-c40363090d18", + "title": "New tile", + "visualType": "multistat", + "pageId": "e813fc9f-4788-43f3-a890-ca213b19d6e9", + "layout": { + "x": 0, + "y": 12, + "width": 3, + "height": 6 + }, + "queryRef": { + "kind": "query", + "queryId": "658a1393-d464-4626-97ed-915df835eda0" + }, + "hideTitle": true, + "visualOptions": { + "multiStat__textSize": "auto", + "multiStat__valueColumn": "operating_mode_label", + "colorRulesDisabled": false, + "colorStyle": "light", + "multiStat__displayOrientation": "horizontal", + "multiStat__labelColumn": "device_id_label", + "multiStat__slot": { + "width": 1, + "height": 2 + }, + "colorRules": [ + { + "id": "b832c4c4-64a6-41b5-bffa-11d82d15cd3b", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "operator": "==", + "column": "operating_mode", + "values": [ + "heating" + ] + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "red", + "tag": "", + "icon": null, + "ruleName": "", + "visualType": "multistat" + }, + { + "id": "a4203fa2-9755-4080-b83b-731edced75c8", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "operator": "==", + "column": "operating_mode", + "values": [ + "cooling" + ] + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "blue", + "tag": "", + "icon": null, + "ruleName": "", + "visualType": "multistat" + } + ] + } + }, + { + "id": "ead1d757-b659-4e8a-b4b3-99b704ad191b", + "title": "HVAC Power Utilization (kWh)", + "visualType": "area", + "pageId": "e813fc9f-4788-43f3-a890-ca213b19d6e9", + "layout": { + "x": 3, + "y": 12, + "width": 8, + "height": 6 + }, + "queryRef": { + "kind": "query", + "queryId": "1fa31e61-b4dd-4471-b5a6-c982c15cd9c8" + }, + "visualOptions": { + "multipleYAxes": { + "base": { + "id": "-1", + "label": "", + "columns": [], + "yAxisMaximumValue": null, + "yAxisMinimumValue": null, + "yAxisScale": "linear", + "horizontalLines": [] + }, + "additional": [], + "showMultiplePanels": true + }, + "hideLegend": true, + "legendLocation": "bottom", + "xColumnTitle": "", + "xColumn": "timestamp", + "yColumns": [ + "power_usage_kwh" + ], + "seriesColumns": [ + "device_id" + ], + "xAxisScale": "linear", + "verticalLine": "", + "crossFilterDisabled": false, + "drillthroughDisabled": false, + "crossFilter": [], + "drillthrough": [] + } + }, + { + "id": "d0be5ee7-a268-4389-8553-a479fe3581ec", + "title": "Refrigerator Temperature (Celsius)", + "visualType": "multistat", + "pageId": "e813fc9f-4788-43f3-a890-ca213b19d6e9", + "layout": { + "x": 3, + "y": 6, + "width": 10, + "height": 6 + }, + "queryRef": { + "kind": "query", + "queryId": "cf05490c-b613-4a3d-b194-d75d840b8fc5" + }, + "visualOptions": { + "multiStat__textSize": "auto", + "multiStat__valueColumn": "temperature_celsius_label", + "colorRulesDisabled": false, + "colorStyle": "light", + "multiStat__displayOrientation": "horizontal", + "multiStat__labelColumn": "device_id", + "multiStat__slot": { + "width": 1, + "height": 2 + }, + "colorRules": [ + { + "id": "c807c2d3-43f7-4af9-8a9e-9e756b71e1d8", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "values": [ + "2" + ], + "operator": ">", + "column": "temperature_celsius" + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "red", + "tag": "Food Safety Risk", + "icon": "warning", + "ruleName": "Temperature Gauge", + "visualType": "multistat" + }, + { + "id": "85140876-c125-4982-ba46-0e018c1d9aec", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "values": [ + "2024-11-01T10:13:50Z" + ], + "operator": ">", + "column": "temperature_celsius" + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "yellow", + "tag": "Sensor Read Error", + "icon": null, + "ruleName": "Sensor Lag", + "visualType": "multistat" + }, + { + "id": "b1060aba-4b62-4d00-91f1-ac8971f074b9", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "operator": "<=", + "column": "temperature_celsius", + "values": [ + "2" + ] + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "green", + "tag": "", + "icon": null, + "ruleName": "", + "visualType": "multistat" + } + ] + } + }, + { + "id": "da08f950-8ba9-4712-b512-225bf790f8d6", + "title": "Temp (Celsius)", + "visualType": "column", + "pageId": "e813fc9f-4788-43f3-a890-ca213b19d6e9", + "layout": { + "x": 11, + "y": 12, + "width": 5, + "height": 6 + }, + "queryRef": { + "kind": "query", + "queryId": "338ebed5-284b-4251-828e-f1eb290c624a" + }, + "visualOptions": { + "multipleYAxes": { + "base": { + "id": "-1", + "label": "", + "columns": [], + "yAxisMaximumValue": 25, + "yAxisMinimumValue": null, + "yAxisScale": "linear", + "horizontalLines": [] + }, + "additional": [], + "showMultiplePanels": false + }, + "hideLegend": true, + "legendLocation": "bottom", + "xColumnTitle": "", + "xColumn": "device_id", + "yColumns": [ + "temperature_celsius" + ], + "seriesColumns": null, + "xAxisScale": "linear", + "verticalLine": "", + "crossFilterDisabled": false, + "drillthroughDisabled": false, + "crossFilter": [], + "drillthrough": [] + } + }, + { + "id": "7bb594f5-7b06-4b5f-870c-524babd709b5", + "title": "Refrigerator Power Utilization (kWh)", + "visualType": "area", + "pageId": "e813fc9f-4788-43f3-a890-ca213b19d6e9", + "layout": { + "x": 13, + "y": 6, + "width": 8, + "height": 6 + }, + "queryRef": { + "kind": "query", + "queryId": "59c08389-4793-425f-b3b1-201ceec1c8f1" + }, + "visualOptions": { + "multipleYAxes": { + "base": { + "id": "-1", + "label": "", + "columns": [], + "yAxisMaximumValue": null, + "yAxisMinimumValue": null, + "yAxisScale": "linear", + "horizontalLines": [] + }, + "additional": [], + "showMultiplePanels": true + }, + "hideLegend": true, + "legendLocation": "bottom", + "xColumnTitle": "", + "xColumn": "timestamp", + "yColumns": [ + "power_usage_kwh" + ], + "seriesColumns": [ + "device_id" + ], + "xAxisScale": "linear", + "verticalLine": "", + "crossFilterDisabled": false, + "drillthroughDisabled": false, + "crossFilter": [], + "drillthrough": [] + } + }, + { + "id": "a3711b00-ce16-4416-b092-a137a55e1688", + "title": "Humidity", + "visualType": "multistat", + "pageId": "e813fc9f-4788-43f3-a890-ca213b19d6e9", + "layout": { + "x": 16, + "y": 12, + "width": 5, + "height": 6 + }, + "queryRef": { + "kind": "query", + "queryId": "1e4dd09f-5439-4b45-91c3-2bf340158b6d" + }, + "visualOptions": { + "multiStat__textSize": "auto", + "multiStat__valueColumn": "humidity_percent_label", + "colorRulesDisabled": false, + "colorStyle": "light", + "multiStat__displayOrientation": "horizontal", + "multiStat__labelColumn": "device_id", + "multiStat__slot": { + "width": 1, + "height": 2 + }, + "colorRules": [ + { + "id": "b832c4c4-64a6-41b5-bffa-11d82d15cd3b", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "operator": "==", + "column": "operating_mode", + "values": [ + "heating" + ] + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "red", + "tag": "", + "icon": null, + "ruleName": "", + "visualType": "multistat" + }, + { + "id": "a4203fa2-9755-4080-b83b-731edced75c8", + "ruleType": "colorByCondition", + "applyToColumn": null, + "hideText": false, + "applyTo": "cells", + "conditions": [ + { + "operator": "==", + "column": "operating_mode", + "values": [ + "cooling" + ] + } + ], + "chainingOperator": "and", + "colorStyle": "bold", + "color": "blue", + "tag": "", + "icon": null, + "ruleName": "", + "visualType": "multistat" + } + ] + } + } + ], + "baseQueries": [ + { + "id": "96a651b3-ce60-4f37-8c85-1db19332b6ec", + "queryId": "02787624-cc81-471a-9dd3-89e876a0b0d4", + "variableName": "test" + } + ], + "parameters": [ + { + "kind": "duration", + "id": "bb1650a2-322a-4c35-acf3-2fecaf349561", + "displayName": "Time range", + "description": "", + "beginVariableName": "_startTime", + "endVariableName": "_endTime", + "defaultValue": { + "kind": "dynamic", + "count": 1, + "unit": "hours" + }, + "showOnPages": { + "kind": "all" + } + } + ], + "dataSources": [ + { + "id": "84a721cf-89b0-46ec-8a2e-24f267bb60e6", + "kind": "kusto-trident", + "clusterUri": "{{KQL_CLUSTER_URI}}", + "database": "{{KQL_DATABASE_ID}}", + "name": "contosohypermarket", + "scopeId": "kusto-trident", + "workspace": "{{FABRIC_WORKSPACE_ID}}" + } + ], + "pages": [ + { + "name": "OT Dashboard", + "id": "e813fc9f-4788-43f3-a890-ca213b19d6e9" + } + ], + "queries": [ + { + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "//Get refrigerator temps\niot_data\n| where equipment_type == \"Refrigerator\"\n| extend d = parse_json(data) \n| extend system_id = d.id\n , door_open = d.door_open\n| summarize arg_max(timestamp, door_open) by device_id\n| extend door_status = case(door_open == true, \"Open\", \"Closed\")\n| extend device_id_label = strcat(device_id, \" Door\")\n| sort by device_id_label asc \n", + "id": "a499aa12-4369-493d-93ea-409aa7dd483c", + "usedVariables": [ + "_endTime", + "_startTime" + ] + }, + { + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "//Light Status Queries\niot_data\n| where equipment_type == \"LightingSystem\"\n| extend d = parse_json(data) \n| extend system_id = d.id\n , status = tostring(d.status)\n| summarize arg_max(timestamp, status) by device_id\n//change the status to Sentence case.\n| extend status_label = strcat(toupper(substring(status, 0, 1)), tolower(substring(status, 1, strlen(status)-1)))\n| sort by device_id asc \n", + "id": "e872f3db-a364-4f27-9c45-6302e6426a0a", + "usedVariables": [ + "_endTime", + "_startTime" + ] + }, + { + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "//Light Brightness Level\niot_data \n| where equipment_type == \"LightingSystem\" \n| where timestamp between (_startTime .. _endTime)\n| extend d = parse_json(data) \n| extend system_id = d.id , brightness_level = todecimal(d.brightness_level) \n| project timestamp, device_id, system_id, brightness_level ", + "id": "15b59907-6b86-47f5-947c-1d824ad91e38", + "usedVariables": [ + "_endTime", + "_startTime" + ] + }, + { + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "//Light Power Utilization\niot_data \n| where equipment_type == \"LightingSystem\" \n//| where device_id == \"LightingSystem01\"\n| where timestamp between (_startTime .. _endTime)\n| extend d = parse_json(data) \n| extend system_id = d.id , power_usage_kwh = todecimal(d.power_usage_kwh) \n| project timestamp, device_id, system_id, power_usage_kwh ", + "id": "baf31768-a72a-4d2f-9fea-7d546122263a", + "usedVariables": [ + "_endTime", + "_startTime" + ] + }, + { + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "// HVAC operating_mode\niot_data\n| where equipment_type == \"HVAC\"\n| extend d = parse_json(data) \n| extend system_id = d.id\n , operating_mode = tostring(d.operating_mode)\n| summarize arg_max(timestamp, operating_mode) by device_id\n| extend device_id_label = strcat(device_id, \" Mode\")\n//change the operating_mode to Sentence case.\n| extend operating_mode_label = strcat(toupper(substring(operating_mode, 0, 1)), tolower(substring(operating_mode, 1, strlen(operating_mode)-1)))\n| sort by device_id asc \n\n", + "id": "658a1393-d464-4626-97ed-915df835eda0", + "usedVariables": [] + }, + { + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "//Light Power Utilization\niot_data \n| where equipment_type == \"HVAC\" \n| where timestamp between (_startTime .. _endTime)\n| extend d = parse_json(data) \n| extend system_id = d.id , power_usage_kwh = todecimal(d.power_usage_kwh) \n| project timestamp, device_id, system_id, power_usage_kwh ", + "id": "1fa31e61-b4dd-4471-b5a6-c982c15cd9c8", + "usedVariables": [ + "_endTime", + "_startTime" + ] + }, + { + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "//Get refrigerator temps\niot_data\n| where equipment_type == \"Refrigerator\"\n| extend d = parse_json(data) \n| extend system_id = d.id\n , temperature_celsius = todecimal(d.temperature_celsius)\n| summarize arg_max(timestamp, temperature_celsius) by device_id\n| extend temperature_celsius_label = strcat(round(temperature_celsius, 2), \"\\u00B0C\")\n| sort by device_id asc \n", + "id": "cf05490c-b613-4a3d-b194-d75d840b8fc5", + "usedVariables": [] + }, + { + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "// HVAC operating_mode\niot_data\n| where equipment_type == \"HVAC\"\n| extend d = parse_json(data) \n| extend system_id = d.id\n , temperature_celsius = todecimal(d.temperature_celsius)\n| summarize arg_max(timestamp, temperature_celsius) by device_id\n| sort by device_id asc \n\n", + "id": "338ebed5-284b-4251-828e-f1eb290c624a", + "usedVariables": [] + }, + { + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "//Light Power Utilization\niot_data \n| where equipment_type == \"Refrigerator\" \n| where timestamp between (_startTime .. _endTime)\n| extend d = parse_json(data) \n| extend system_id = d.id , power_usage_kwh = todecimal(d.power_usage_kwh) \n| project timestamp, device_id, system_id, power_usage_kwh ", + "id": "59c08389-4793-425f-b3b1-201ceec1c8f1", + "usedVariables": [ + "_endTime", + "_startTime" + ] + }, + { + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "// HVAC humidity\niot_data\n| where equipment_type == \"HVAC\"\n| extend d = parse_json(data) \n| extend system_id = d.id\n , humidity_percent = tostring(d.humidity_percent)\n| summarize arg_max(timestamp, humidity_percent) by device_id\n| extend humidity_percent_label = strcat(humidity_percent, \"%\")\n| sort by device_id asc \n\n", + "id": "1e4dd09f-5439-4b45-91c3-2bf340158b6d", + "usedVariables": [] + }, + { + "id": "02787624-cc81-471a-9dd3-89e876a0b0d4", + "dataSource": { + "kind": "inline", + "dataSourceId": "84a721cf-89b0-46ec-8a2e-24f267bb60e6" + }, + "text": "// Please enter your KQL query (Example):\n// \n// | where between (['_startTime'] .. ['_endTime']) // Time range filtering\n// | take 100\niot_data\n| where device_id == \"SmartShelf02\"", + "usedVariables": [ + "_endTime", + "_startTime" + ] + } + ] +} \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/icons/contoso-hypermarket.png b/azure_jumpstart_ag/artifacts/icons/contoso-hypermarket.png new file mode 100644 index 0000000000..379dae8644 Binary files /dev/null and b/azure_jumpstart_ag/artifacts/icons/contoso-hypermarket.png differ diff --git a/azure_jumpstart_ag/artifacts/icons/contoso-hypermarket.svg b/azure_jumpstart_ag/artifacts/icons/contoso-hypermarket.svg new file mode 100644 index 0000000000..44645f157a --- /dev/null +++ b/azure_jumpstart_ag/artifacts/icons/contoso-hypermarket.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/azure_jumpstart_ag/artifacts/kubernetes/K3s/installK3s.sh b/azure_jumpstart_ag/artifacts/kubernetes/K3s/installK3s.sh new file mode 100644 index 0000000000..dc68270bd4 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/kubernetes/K3s/installK3s.sh @@ -0,0 +1,321 @@ +#!/bin/bash +sudo apt-get update + +sudo sed -i "s/PasswordAuthentication no/PasswordAuthentication yes/" /etc/ssh/sshd_config +sudo adduser staginguser --gecos "First Last,RoomNumber,WorkPhone,HomePhone" --disabled-password +sudo echo "staginguser:ArcPassw0rd" | sudo chpasswd + +# Injecting environment variables +echo '#!/bin/bash' >> vars.sh +echo $adminUsername:$1 | awk '{print substr($1,2); }' >> vars.sh +echo $subscriptionId:$2 | awk '{print substr($1,2); }' >> vars.sh +echo $vmName:$3 | awk '{print substr($1,2); }' >> vars.sh +echo $location:$4 | awk '{print substr($1,2); }' >> vars.sh +echo $stagingStorageAccountName:$5 | awk '{print substr($1,2); }' >> vars.sh +echo $logAnalyticsWorkspace:$6 | awk '{print substr($1,2); }' >> vars.sh +echo $templateBaseUrl:$7 | awk '{print substr($1,2); }' >> vars.sh +echo $storageContainerName:$8 | awk '{print substr($1,2); }' >> vars.sh +echo $k3sControlPlane:$9 | awk '{print substr($1,2); }' >> vars.sh +echo $resourceGroup:$10| awk '{print substr($1,2); }' >> vars.sh +echo $deployGPUNodes:$11| awk '{print substr($1,2); }' >> vars.sh + +sed -i '2s/^/export adminUsername=/' vars.sh +sed -i '3s/^/export subscriptionId=/' vars.sh +sed -i '4s/^/export vmName=/' vars.sh +sed -i '5s/^/export location=/' vars.sh +sed -i '6s/^/export stagingStorageAccountName=/' vars.sh +sed -i '7s/^/export logAnalyticsWorkspace=/' vars.sh +sed -i '8s/^/export templateBaseUrl=/' vars.sh +sed -i '9s/^/export storageContainerName=/' vars.sh +sed -i '10s/^/export k3sControlPlane=/' vars.sh +sed -i '11s/^/export resourceGroup=/' vars.sh +sed -i '12s/^/export deployGPUNodes=/' vars.sh + +export vmName=$3 + +# Save the original stdout and stderr +exec 3>&1 4>&2 + +exec >installK3s-${vmName}.log +exec 2>&1 + +# Set k3 deployment variables +export K3S_VERSION="1.29.6+k3s2" # Do not change! + +chmod +x vars.sh +. ./vars.sh + +# Creating login message of the day (motd) +curl -v -o /etc/profile.d/welcomeK3s.sh ${templateBaseUrl}artifacts/welcomeK3s.sh + +# Syncing this script log to 'jumpstart_logs' directory for ease of troubleshooting +sudo -u $adminUsername mkdir -p /home/${adminUsername}/jumpstart_logs +while sleep 1; do sudo -s rsync -a /var/lib/waagent/custom-script/download/0/installK3s-$vmName.log /home/${adminUsername}/jumpstart_logs/installK3s-$vmName.log; done & + +# Function to check if dpkg lock is in place +check_dpkg_lock() { + while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do + echo "Waiting for other package management processes to complete..." + sleep 5 + done +} +# Run the lock check before attempting the installation +check_dpkg_lock + +# Downloading azcopy +echo "" +echo "Downloading azcopy" +echo "" +wget -O azcopy.tar.gz https://aka.ms/downloadazcopy-v10-linux +if [[ $? -ne 0 ]]; then + echo "ERROR: Failed to download azcopy" + exit 1 +fi + +tar -xf azcopy.tar.gz +sudo mv azcopy_linux_amd64_*/azcopy /usr/local/bin/azcopy +sudo chmod +x /usr/local/bin/azcopy + +# Authorize azcopy by using a system-wide managed identity +export AZCOPY_AUTO_LOGIN_TYPE=MSI + +# Run the lock check before attempting the installation +check_dpkg_lock + +# Installing Azure CLI & Azure Arc extensions +max_retries=5 +retry_count=0 +success=false + +while [ $retry_count -lt $max_retries ]; do + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + if [ $? -eq 0 ]; then + success=true + break + else + echo "Failed to install Az CLI. Retrying (Attempt $((retry_count+1)))..." + retry_count=$((retry_count+1)) + sleep 10 + fi +done + +echo "" +echo "Log in to Azure" +echo "" +for i in {1..5}; do + sudo -u $adminUsername az login --identity + if [[ $? -eq 0 ]]; then + break + fi + sleep 15 + if [[ $i -eq 5 ]]; then + echo "Error: Failed to login to Azure after 5 retries" + exit 1 + fi +done + +sudo -u $adminUsername az account set --subscription $subscriptionId +az -v + +check_dpkg_lock + +if [[ "$k3sControlPlane" == "true" ]]; then + + # Installing Azure Arc extensions + echo "" + echo "Installing Azure Arc extensions" + echo "" + sudo -u $adminUsername az extension add --name connectedk8s --version 1.9.3 + sudo -u $adminUsername az extension add --name k8s-configuration + sudo -u $adminUsername az extension add --name k8s-extension + + # Installing Rancher K3s cluster (single control plane) + echo "" + echo "Installing Rancher K3s cluster" + echo "" + publicIp=$(hostname -i) + sudo mkdir ~/.kube + sudo -u $adminUsername mkdir /home/${adminUsername}/.kube + curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --disable traefik --disable servicelb --node-ip ${publicIp} --node-external-ip ${publicIp} --bind-address ${publicIp} --tls-san ${publicIp}" INSTALL_K3S_VERSION=v${K3S_VERSION} K3S_KUBECONFIG_MODE="644" sh - + if [[ $? -ne 0 ]]; then + echo "ERROR: K3s installation failed" + exit 1 + fi + # Renaming default context to k3s cluster name + context=$(echo $storageContainerName | sed 's/-[^-]*$//') + sudo kubectl config rename-context default $context --kubeconfig /etc/rancher/k3s/k3s.yaml + sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config + sudo cp /etc/rancher/k3s/k3s.yaml /home/${adminUsername}/.kube/config + sudo cp /etc/rancher/k3s/k3s.yaml /home/${adminUsername}/.kube/config.staging + sudo chown -R $adminUsername /home/${adminUsername}/.kube/ + sudo chown -R staginguser /home/${adminUsername}/.kube/config.staging + + # Installing Helm 3 + echo "" + echo "Installing Helm" + echo "" + sudo snap install helm --classic + if [[ $? -ne 0 ]]; then + echo "ERROR: Helm installation failed" + exit 1 + fi + + echo "" + echo "Making sure Rancher K3s cluster is ready..." + echo "" + sudo kubectl wait --for=condition=Available --timeout=60s --all deployments -A >/dev/null + sudo kubectl get nodes -o wide | expand | awk 'length($0) > length(longest) { longest = $0 } { lines[NR] = $0 } END { gsub(/./, "=", longest); print "/=" longest "=\\"; n = length(longest); for(i = 1; i <= NR; ++i) { printf("| %s %*s\n", lines[i], n - length(lines[i]) + 1, "|"); } print "\\=" longest "=/" }' + + # Copying Rancher K3s kubeconfig file to staging storage account + echo "" + echo "Copying Rancher K3s kubeconfig file to staging storage account" + echo "" + localPath="/home/$adminUsername/.kube/config" + k3sClusterNodeConfig="/home/$adminUsername/k3sClusterNodeConfig.yaml" + echo "k3sNodeToken: $(sudo cat /var/lib/rancher/k3s/server/node-token)" >> $k3sClusterNodeConfig + echo "k3sClusterIp: $publicIp" >> $k3sClusterNodeConfig + # Copying kubeconfig file to staging storage account + azcopy make "https://$stagingStorageAccountName.blob.core.windows.net/$storageContainerName" + azcopy cp $localPath "https://$stagingStorageAccountName.blob.core.windows.net/$storageContainerName/config" + azcopy cp $k3sClusterNodeConfig "https://$stagingStorageAccountName.blob.core.windows.net/$storageContainerName/k3sClusterNodeConfig.yaml" + + # Onboard the cluster to Azure Arc + echo "" + echo "Onboarding the cluster to Azure Arc" + echo "" + resourceGroup=$(sudo -u $adminUsername az resource list --query "[?name=='$stagingStorageAccountName']".[resourceGroup] --resource-type "Microsoft.Storage/storageAccounts" -o tsv) + workspaceResourceId=$(sudo -u $adminUsername az resource show --resource-group $resourceGroup --name $logAnalyticsWorkspace --resource-type "Microsoft.OperationalInsights/workspaces" --query id -o tsv) + echo "Log Analytics workspace id $workspaceResourceId" + + max_retries=5 + retry_count=0 + success=false + + while [ $retry_count -lt $max_retries ]; do + sudo -u $adminUsername az connectedk8s connect --name $vmName --resource-group $resourceGroup --location $location + if [ $? -eq 0 ]; then + success=true + break + else + echo "Failed to onboard cluster to Azure Arc. Retrying (Attempt $((retry_count+1)))..." + retry_count=$((retry_count+1)) + sleep 10 + fi + done + + if [ "$success" = false ]; then + echo "Error: Failed to onboard the cluster to Azure Arc after $max_retries attempts." + exit 1 + fi + + echo "Onboarding the k3s cluster to Azure Arc completed" + + # Verify if cluster is connected to Azure Arc successfully + connectedClusterInfo=$(sudo -u $adminUsername az connectedk8s show --name $vmName --resource-group $resourceGroup) + echo "Connected cluster info: $connectedClusterInfo" + + # Wait +# Function to check if an extension is already installed +is_extension_installed() { + extension_name=$1 + extension_count=$(sudo -u $adminUsername az k8s-extension list --cluster-name $vmName --resource-group $resourceGroup --cluster-type connectedClusters --query "[?name=='$extension_name'] | length(@)") + + if [ "$extension_count" -gt 0 ]; then + return 0 # Extension is installed + else + return 1 # Extension is not installed + fi +} + +# Enabling Container Insights and Microsoft Defender for Containers cluster extensions +echo "" +echo "Enabling Container Insights and Microsoft Defender for Containers cluster extensions" +echo "" + +# Check and install azuremonitor-containers extension +if is_extension_installed "azuremonitor-containers"; then + echo "Extension 'azuremonitor-containers' is already installed." +else + echo "Extension 'azuremonitor-containers' is not installed - triggering installation" + sudo -u $adminUsername az k8s-extension create -n "azuremonitor-containers" --cluster-name $vmName --resource-group $resourceGroup --cluster-type connectedClusters --extension-type Microsoft.AzureMonitor.Containers --configuration-settings logAnalyticsWorkspaceResourceID=$workspaceResourceId --only-show-errors +fi + +# Check and install microsoft.azuredefender.kubernetes extension +if is_extension_installed "microsoft.azuredefender.kubernetes"; then + echo "Extension 'microsoft.azuredefender.kubernetes' is already installed." +else + echo "Extension 'microsoft.azuredefender.kubernetes' is not installed - triggering installation" + sudo -u $adminUsername az k8s-extension create -n "microsoft.azuredefender.kubernetes" --cluster-name $vmName --resource-group $resourceGroup --cluster-type connectedClusters --extension-type Microsoft.AzureDefender.Kubernetes --configuration-settings logAnalyticsWorkspaceResourceID=$workspaceResourceId --only-show-errors +fi + +# Enabling Azure Policy for Kubernetes on the cluster +echo "" +echo "Enabling Azure Policy for Kubernetes on the cluster" +echo "" + +# Check and install arc-azurepolicy extension +if is_extension_installed "azurepolicy"; then + echo "Extension 'azurepolicy' is already installed." +else + echo "Extension 'azurepolicy' is not installed - triggering installation" + sudo -u $adminUsername az k8s-extension create --name "azurepolicy" --cluster-name $vmName --resource-group $resourceGroup --cluster-type connectedClusters --extension-type Microsoft.PolicyInsights --only-show-errors +fi + +else + # Downloading k3s control plane details + echo "" + echo "Downloading k3s control plane details" + echo "" + k3sClusterNodeConfigYaml="k3sClusterNodeConfig.yaml" + sleep 60 + + azcopy cp --check-md5 FailIfDifferentOrMissing "https://$stagingStorageAccountName.blob.core.windows.net/$storageContainerName/$k3sClusterNodeConfigYaml" "/home/$adminUsername/$k3sClusterNodeConfigYaml" + + # Installing Rancher K3s cluster (single worker node) + echo "" + echo "Installing Rancher K3s cluster node" + echo "" + k3sNodeToken=$(grep 'k3sNodeToken' "/home/$adminUsername/$k3sClusterNodeConfigYaml" | awk '{print $2}') + k3sClusterIp=$(grep 'k3sClusterIp' "/home/$adminUsername/$k3sClusterNodeConfigYaml" | awk '{print $2}') + curl -sfL https://get.k3s.io | K3S_URL=https://${k3sClusterIp}:6443 INSTALL_K3S_VERSION=v${K3S_VERSION} K3S_TOKEN=${k3sNodeToken} sh - + if [[ $? -ne 0 ]]; then + echo "ERROR: Failed to add k3s worker nodes" + exit 1 + fi + + sudo service sshd restart +fi + +if [ "$deployGPUNodes" == "true" ] && [ "$k3sControlPlane" == "false" ]; then + # Installing NVIDIA GPU drivers + echo "" + echo "Installing NVIDIA GPU drivers" + echo "" + sudo curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ + && sudo curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ + sudo sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ + sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list + sudo apt-get update -y + sudo apt-get install -y nvidia-container-toolkit + # Configure K3s to use nvidia-ctk + sudo nvidia-ctk runtime configure --runtime=containerd + sudo systemctl restart k3s +fi + + if [[ $? -ne 0 ]]; then + echo "ERROR: Failed to install NVIDIA GPU drivers" + exit 1 + fi + + # Installing NVIDIA container toolkit + +# Uploading this script log to staging storage for ease of troubleshooting +echo "" +echo "Uploading the script logs to staging storage" +echo "" +exec 1>&3 2>&4 # Further commands will now output to the original stdout and stderr and not the log file +log="/home/$adminUsername/jumpstart_logs/installK3s-$vmName.log" +storageContainerNameLower=$(echo $storageContainerName | tr '[:upper:]' '[:lower:]') +azcopy cp $log "https://$stagingStorageAccountName.blob.core.windows.net/$storageContainerNameLower/installK3s-$vmName.log" --check-length=false >/dev/null 2>&1 + +exit 0 \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/kubernetes/K3s/kubeVipDaemon.yml b/azure_jumpstart_ag/artifacts/kubernetes/K3s/kubeVipDaemon.yml new file mode 100644 index 0000000000..22bbac5d2b --- /dev/null +++ b/azure_jumpstart_ag/artifacts/kubernetes/K3s/kubeVipDaemon.yml @@ -0,0 +1,88 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/name: kube-vip-ds + app.kubernetes.io/version: v0.7.0 + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + app.kubernetes.io/name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + app.kubernetes.io/name: kube-vip-ds + app.kubernetes.io/version: v0.7.0 + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-role.kubernetes.io/master + operator: Exists + - matchExpressions: + - key: node-role.kubernetes.io/control-plane + operator: Exists + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: dns_mode + value: first + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: svc_enable + value: "true" + - name: svc_leasename + value: plndr-svcs-lock + - name: vip_leaderelection + value: "true" + - name: vip_leasename + value: plndr-cp-lock + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: address + value: "k3sVIPPlaceholder" + - name: prometheus_server + value: :2112 + image: ghcr.io/kube-vip/kube-vip:v0.7.0 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + hostNetwork: true + serviceAccountName: kube-vip + tolerations: + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/kubernetes/K3s/kubeVipRbac.yml b/azure_jumpstart_ag/artifacts/kubernetes/K3s/kubeVipRbac.yml new file mode 100644 index 0000000000..e966a8c1f5 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/kubernetes/K3s/kubeVipRbac.yml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kube-vip + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:kube-vip-role +rules: + - apiGroups: [""] + resources: ["services/status"] + verbs: ["update"] + - apiGroups: [""] + resources: ["services", "endpoints"] + verbs: ["list","get","watch", "update"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","get","watch", "update", "patch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["list", "get", "watch", "update", "create"] + - apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["list","get","watch", "update"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system:kube-vip-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:kube-vip-role +subjects: +- kind: ServiceAccount + name: kube-vip + namespace: kube-system \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/kubernetes/K3s/longhorn.yaml b/azure_jumpstart_ag/artifacts/kubernetes/K3s/longhorn.yaml new file mode 100644 index 0000000000..b03ab89440 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/kubernetes/K3s/longhorn.yaml @@ -0,0 +1,4571 @@ +--- +# Builtin: "helm template" does not respect --create-namespace +apiVersion: v1 +kind: Namespace +metadata: + name: longhorn-system +--- +# Source: longhorn/templates/priorityclass.yaml +apiVersion: scheduling.k8s.io/v1 +kind: PriorityClass +metadata: + name: "longhorn-critical" + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 +description: "Ensure Longhorn pods have the highest priority to prevent any unexpected eviction by the Kubernetes scheduler under node pressure" +globalDefault: false +preemptionPolicy: PreemptLowerPriority +value: 1000000000 +--- +# Source: longhorn/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: longhorn-service-account + namespace: longhorn-system + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 +--- +# Source: longhorn/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: longhorn-ui-service-account + namespace: longhorn-system + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 +--- +# Source: longhorn/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: longhorn-support-bundle + namespace: longhorn-system + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 +--- +# Source: longhorn/templates/default-setting.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: longhorn-default-setting + namespace: longhorn-system + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 +data: + default-setting.yaml: |- + priority-class: longhorn-critical +--- +# Source: longhorn/templates/storageclass.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: longhorn-storageclass + namespace: longhorn-system + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 +data: + storageclass.yaml: | + kind: StorageClass + apiVersion: storage.k8s.io/v1 + metadata: + name: longhorn + annotations: + storageclass.kubernetes.io/is-default-class: "true" + provisioner: driver.longhorn.io + allowVolumeExpansion: true + reclaimPolicy: "Delete" + volumeBindingMode: Immediate + parameters: + numberOfReplicas: "1" + staleReplicaTimeout: "30" + fromBackup: "" + fsType: "ext4" + dataLocality: "disabled" +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: backingimagedatasources.longhorn.io +spec: + group: longhorn.io + names: + kind: BackingImageDataSource + listKind: BackingImageDataSourceList + plural: backingimagedatasources + shortNames: + - lhbids + singular: backingimagedatasource + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The current state of the pod used to provision the backing image file from source + jsonPath: .status.currentState + name: State + type: string + - description: The data source type + jsonPath: .spec.sourceType + name: SourceType + type: string + - description: The node the backing image file will be prepared on + jsonPath: .spec.nodeID + name: Node + type: string + - description: The disk the backing image file will be prepared on + jsonPath: .spec.diskUUID + name: DiskUUID + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: BackingImageDataSource is where Longhorn stores backing image data source object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The system generated UUID of the provisioned backing image file + jsonPath: .spec.uuid + name: UUID + type: string + - description: The current state of the pod used to provision the backing image file from source + jsonPath: .status.currentState + name: State + type: string + - description: The data source type + jsonPath: .spec.sourceType + name: SourceType + type: string + - description: The backing image file size + jsonPath: .status.size + name: Size + type: string + - description: The node the backing image file will be prepared on + jsonPath: .spec.nodeID + name: Node + type: string + - description: The disk the backing image file will be prepared on + jsonPath: .spec.diskUUID + name: DiskUUID + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: BackingImageDataSource is where Longhorn stores backing image data source object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BackingImageDataSourceSpec defines the desired state of the Longhorn backing image data source + properties: + checksum: + type: string + diskPath: + type: string + diskUUID: + type: string + fileTransferred: + type: boolean + nodeID: + type: string + parameters: + additionalProperties: + type: string + type: object + sourceType: + enum: + - download + - upload + - export-from-volume + - restore + type: string + uuid: + type: string + type: object + status: + description: BackingImageDataSourceStatus defines the observed state of the Longhorn backing image data source + properties: + checksum: + type: string + currentState: + type: string + ip: + type: string + message: + type: string + ownerID: + type: string + progress: + type: integer + runningParameters: + additionalProperties: + type: string + nullable: true + type: object + size: + format: int64 + type: integer + storageIP: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: backingimagemanagers.longhorn.io +spec: + group: longhorn.io + names: + kind: BackingImageManager + listKind: BackingImageManagerList + plural: backingimagemanagers + shortNames: + - lhbim + singular: backingimagemanager + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The current state of the manager + jsonPath: .status.currentState + name: State + type: string + - description: The image the manager pod will use + jsonPath: .spec.image + name: Image + type: string + - description: The node the manager is on + jsonPath: .spec.nodeID + name: Node + type: string + - description: The disk the manager is responsible for + jsonPath: .spec.diskUUID + name: DiskUUID + type: string + - description: The disk path the manager is using + jsonPath: .spec.diskPath + name: DiskPath + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: BackingImageManager is where Longhorn stores backing image manager object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The current state of the manager + jsonPath: .status.currentState + name: State + type: string + - description: The image the manager pod will use + jsonPath: .spec.image + name: Image + type: string + - description: The node the manager is on + jsonPath: .spec.nodeID + name: Node + type: string + - description: The disk the manager is responsible for + jsonPath: .spec.diskUUID + name: DiskUUID + type: string + - description: The disk path the manager is using + jsonPath: .spec.diskPath + name: DiskPath + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: BackingImageManager is where Longhorn stores backing image manager object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BackingImageManagerSpec defines the desired state of the Longhorn backing image manager + properties: + backingImages: + additionalProperties: + type: string + type: object + diskPath: + type: string + diskUUID: + type: string + image: + type: string + nodeID: + type: string + type: object + status: + description: BackingImageManagerStatus defines the observed state of the Longhorn backing image manager + properties: + apiMinVersion: + type: integer + apiVersion: + type: integer + backingImageFileMap: + additionalProperties: + properties: + currentChecksum: + type: string + message: + type: string + name: + type: string + progress: + type: integer + senderManagerAddress: + type: string + sendingReference: + type: integer + size: + format: int64 + type: integer + state: + type: string + uuid: + type: string + type: object + nullable: true + type: object + currentState: + type: string + ip: + type: string + ownerID: + type: string + storageIP: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: backingimages.longhorn.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: longhorn-conversion-webhook + namespace: longhorn-system + path: /v1/webhook/conversion + port: 9501 + conversionReviewVersions: + - v1beta2 + - v1beta1 + group: longhorn.io + names: + kind: BackingImage + listKind: BackingImageList + plural: backingimages + shortNames: + - lhbi + singular: backingimage + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The backing image name + jsonPath: .spec.image + name: Image + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: BackingImage is where Longhorn stores backing image object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The system generated UUID + jsonPath: .status.uuid + name: UUID + type: string + - description: The source of the backing image file data + jsonPath: .spec.sourceType + name: SourceType + type: string + - description: The backing image file size in each disk + jsonPath: .status.size + name: Size + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: BackingImage is where Longhorn stores backing image object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BackingImageSpec defines the desired state of the Longhorn backing image + properties: + checksum: + type: string + disks: + additionalProperties: + type: string + type: object + sourceParameters: + additionalProperties: + type: string + type: object + sourceType: + enum: + - download + - upload + - export-from-volume + - restore + type: string + type: object + status: + description: BackingImageStatus defines the observed state of the Longhorn backing image status + properties: + checksum: + type: string + diskFileStatusMap: + additionalProperties: + properties: + lastStateTransitionTime: + type: string + message: + type: string + progress: + type: integer + state: + type: string + type: object + nullable: true + type: object + diskLastRefAtMap: + additionalProperties: + type: string + nullable: true + type: object + ownerID: + type: string + size: + format: int64 + type: integer + uuid: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + longhorn-manager: "" + name: backupbackingimages.longhorn.io +spec: + group: longhorn.io + names: + kind: BackupBackingImage + listKind: BackupBackingImageList + plural: backupbackingimages + shortNames: + - lhbbi + singular: backupbackingimage + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The backing image name + jsonPath: .status.backingImage + name: BackingImage + type: string + - description: The backing image size + jsonPath: .status.size + name: Size + type: string + - description: The backing image backup upload finished time + jsonPath: .status.backupCreatedAt + name: BackupCreatedAt + type: string + - description: The backing image backup state + jsonPath: .status.state + name: State + type: string + - description: The last synced time + jsonPath: .status.lastSyncedAt + name: LastSyncedAt + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: BackupBackingImage is where Longhorn stores backing image backup object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BackupBackingImageSpec defines the desired state of the Longhorn backing image backup + properties: + labels: + additionalProperties: + type: string + description: The labels of backing image backup. + type: object + syncRequestedAt: + description: The time to request run sync the remote backing image backup. + format: date-time + nullable: true + type: string + userCreated: + description: Is this CR created by user through API or UI. Required + type: boolean + required: + - userCreated + type: object + status: + description: BackupBackingImageStatus defines the observed state of the Longhorn backing image backup + properties: + backingImage: + description: The backing image name. + type: string + backupCreatedAt: + description: The backing image backup upload finished time. + type: string + checksum: + description: The checksum of the backing image. + type: string + compressionMethod: + description: Compression method + type: string + error: + description: The error message when taking the backing image backup. + type: string + labels: + additionalProperties: + type: string + description: The labels of backing image backup. + nullable: true + type: object + lastSyncedAt: + description: The last time that the backing image backup was synced with the remote backup target. + format: date-time + nullable: true + type: string + managerAddress: + description: The address of the backing image manager that runs backing image backup. + type: string + messages: + additionalProperties: + type: string + description: The error messages when listing or inspecting backing image backup. + nullable: true + type: object + ownerID: + description: The node ID on which the controller is responsible to reconcile this CR. + type: string + progress: + description: The backing image backup progress. + type: integer + size: + description: The backing image size. + format: int64 + type: integer + state: + description: The backing image backup creation state. Can be "", "InProgress", "Completed", "Error", "Unknown". + type: string + url: + description: The backing image backup URL. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: backups.longhorn.io +spec: + group: longhorn.io + names: + kind: Backup + listKind: BackupList + plural: backups + shortNames: + - lhb + singular: backup + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The snapshot name + jsonPath: .status.snapshotName + name: SnapshotName + type: string + - description: The snapshot size + jsonPath: .status.size + name: SnapshotSize + type: string + - description: The snapshot creation time + jsonPath: .status.snapshotCreatedAt + name: SnapshotCreatedAt + type: string + - description: The backup state + jsonPath: .status.state + name: State + type: string + - description: The backup last synced time + jsonPath: .status.lastSyncedAt + name: LastSyncedAt + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: Backup is where Longhorn stores backup object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The snapshot name + jsonPath: .status.snapshotName + name: SnapshotName + type: string + - description: The snapshot size + jsonPath: .status.size + name: SnapshotSize + type: string + - description: The snapshot creation time + jsonPath: .status.snapshotCreatedAt + name: SnapshotCreatedAt + type: string + - description: The backup state + jsonPath: .status.state + name: State + type: string + - description: The backup last synced time + jsonPath: .status.lastSyncedAt + name: LastSyncedAt + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: Backup is where Longhorn stores backup object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BackupSpec defines the desired state of the Longhorn backup + properties: + labels: + additionalProperties: + type: string + description: The labels of snapshot backup. + type: object + snapshotName: + description: The snapshot name. + type: string + syncRequestedAt: + description: The time to request run sync the remote backup. + format: date-time + nullable: true + type: string + type: object + status: + description: BackupStatus defines the observed state of the Longhorn backup + properties: + backupCreatedAt: + description: The snapshot backup upload finished time. + type: string + compressionMethod: + description: Compression method + type: string + error: + description: The error message when taking the snapshot backup. + type: string + labels: + additionalProperties: + type: string + description: The labels of snapshot backup. + nullable: true + type: object + lastSyncedAt: + description: The last time that the backup was synced with the remote backup target. + format: date-time + nullable: true + type: string + messages: + additionalProperties: + type: string + description: The error messages when calling longhorn engine on listing or inspecting backups. + nullable: true + type: object + ownerID: + description: The node ID on which the controller is responsible to reconcile this backup CR. + type: string + progress: + description: The snapshot backup progress. + type: integer + replicaAddress: + description: The address of the replica that runs snapshot backup. + type: string + size: + description: The snapshot size. + type: string + snapshotCreatedAt: + description: The snapshot creation time. + type: string + snapshotName: + description: The snapshot name. + type: string + state: + description: The backup creation state. Can be "", "InProgress", "Completed", "Error", "Unknown". + type: string + url: + description: The snapshot backup URL. + type: string + volumeBackingImageName: + description: The volume's backing image name. + type: string + volumeCreated: + description: The volume creation time. + type: string + volumeName: + description: The volume name. + type: string + volumeSize: + description: The volume size. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: backuptargets.longhorn.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: longhorn-conversion-webhook + namespace: longhorn-system + path: /v1/webhook/conversion + port: 9501 + conversionReviewVersions: + - v1beta2 + - v1beta1 + group: longhorn.io + names: + kind: BackupTarget + listKind: BackupTargetList + plural: backuptargets + shortNames: + - lhbt + singular: backuptarget + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The backup target URL + jsonPath: .spec.backupTargetURL + name: URL + type: string + - description: The backup target credential secret + jsonPath: .spec.credentialSecret + name: Credential + type: string + - description: The backup target poll interval + jsonPath: .spec.pollInterval + name: LastBackupAt + type: string + - description: Indicate whether the backup target is available or not + jsonPath: .status.available + name: Available + type: boolean + - description: The backup target last synced time + jsonPath: .status.lastSyncedAt + name: LastSyncedAt + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: BackupTarget is where Longhorn stores backup target object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The backup target URL + jsonPath: .spec.backupTargetURL + name: URL + type: string + - description: The backup target credential secret + jsonPath: .spec.credentialSecret + name: Credential + type: string + - description: The backup target poll interval + jsonPath: .spec.pollInterval + name: LastBackupAt + type: string + - description: Indicate whether the backup target is available or not + jsonPath: .status.available + name: Available + type: boolean + - description: The backup target last synced time + jsonPath: .status.lastSyncedAt + name: LastSyncedAt + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: BackupTarget is where Longhorn stores backup target object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BackupTargetSpec defines the desired state of the Longhorn backup target + properties: + backupTargetURL: + description: The backup target URL. + type: string + credentialSecret: + description: The backup target credential secret. + type: string + pollInterval: + description: The interval that the cluster needs to run sync with the backup target. + type: string + syncRequestedAt: + description: The time to request run sync the remote backup target. + format: date-time + nullable: true + type: string + type: object + status: + description: BackupTargetStatus defines the observed state of the Longhorn backup target + properties: + available: + description: Available indicates if the remote backup target is available or not. + type: boolean + conditions: + description: Records the reason on why the backup target is unavailable. + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + lastSyncedAt: + description: The last time that the controller synced with the remote backup target. + format: date-time + nullable: true + type: string + ownerID: + description: The node ID on which the controller is responsible to reconcile this backup target CR. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: backupvolumes.longhorn.io +spec: + group: longhorn.io + names: + kind: BackupVolume + listKind: BackupVolumeList + plural: backupvolumes + shortNames: + - lhbv + singular: backupvolume + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The backup volume creation time + jsonPath: .status.createdAt + name: CreatedAt + type: string + - description: The backup volume last backup name + jsonPath: .status.lastBackupName + name: LastBackupName + type: string + - description: The backup volume last backup time + jsonPath: .status.lastBackupAt + name: LastBackupAt + type: string + - description: The backup volume last synced time + jsonPath: .status.lastSyncedAt + name: LastSyncedAt + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: BackupVolume is where Longhorn stores backup volume object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The backup volume creation time + jsonPath: .status.createdAt + name: CreatedAt + type: string + - description: The backup volume last backup name + jsonPath: .status.lastBackupName + name: LastBackupName + type: string + - description: The backup volume last backup time + jsonPath: .status.lastBackupAt + name: LastBackupAt + type: string + - description: The backup volume last synced time + jsonPath: .status.lastSyncedAt + name: LastSyncedAt + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: BackupVolume is where Longhorn stores backup volume object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BackupVolumeSpec defines the desired state of the Longhorn backup volume + properties: + syncRequestedAt: + description: The time to request run sync the remote backup volume. + format: date-time + nullable: true + type: string + type: object + status: + description: BackupVolumeStatus defines the observed state of the Longhorn backup volume + properties: + backingImageChecksum: + description: the backing image checksum. + type: string + backingImageName: + description: The backing image name. + type: string + createdAt: + description: The backup volume creation time. + type: string + dataStored: + description: The backup volume block count. + type: string + labels: + additionalProperties: + type: string + description: The backup volume labels. + nullable: true + type: object + lastBackupAt: + description: The latest volume backup time. + type: string + lastBackupName: + description: The latest volume backup name. + type: string + lastModificationTime: + description: The backup volume config last modification time. + format: date-time + nullable: true + type: string + lastSyncedAt: + description: The last time that the backup volume was synced into the cluster. + format: date-time + nullable: true + type: string + messages: + additionalProperties: + type: string + description: The error messages when call longhorn engine on list or inspect backup volumes. + nullable: true + type: object + ownerID: + description: The node ID on which the controller is responsible to reconcile this backup volume CR. + type: string + size: + description: The backup volume size. + type: string + storageClassName: + description: the storage class name of pv/pvc binding with the volume. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: engineimages.longhorn.io +spec: + preserveUnknownFields: false + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: longhorn-conversion-webhook + namespace: longhorn-system + path: /v1/webhook/conversion + port: 9501 + conversionReviewVersions: + - v1beta2 + - v1beta1 + group: longhorn.io + names: + kind: EngineImage + listKind: EngineImageList + plural: engineimages + shortNames: + - lhei + singular: engineimage + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: State of the engine image + jsonPath: .status.state + name: State + type: string + - description: The Longhorn engine image + jsonPath: .spec.image + name: Image + type: string + - description: Number of resources using the engine image + jsonPath: .status.refCount + name: RefCount + type: integer + - description: The build date of the engine image + jsonPath: .status.buildDate + name: BuildDate + type: date + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: EngineImage is where Longhorn stores engine image object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: Compatibility of the engine image + jsonPath: .status.incompatible + name: Incompatible + type: boolean + - description: State of the engine image + jsonPath: .status.state + name: State + type: string + - description: The Longhorn engine image + jsonPath: .spec.image + name: Image + type: string + - description: Number of resources using the engine image + jsonPath: .status.refCount + name: RefCount + type: integer + - description: The build date of the engine image + jsonPath: .status.buildDate + name: BuildDate + type: date + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: EngineImage is where Longhorn stores engine image object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: EngineImageSpec defines the desired state of the Longhorn engine image + properties: + image: + minLength: 1 + type: string + required: + - image + type: object + status: + description: EngineImageStatus defines the observed state of the Longhorn engine image + properties: + buildDate: + type: string + cliAPIMinVersion: + type: integer + cliAPIVersion: + type: integer + conditions: + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + controllerAPIMinVersion: + type: integer + controllerAPIVersion: + type: integer + dataFormatMinVersion: + type: integer + dataFormatVersion: + type: integer + gitCommit: + type: string + incompatible: + type: boolean + noRefSince: + type: string + nodeDeploymentMap: + additionalProperties: + type: boolean + nullable: true + type: object + ownerID: + type: string + refCount: + type: integer + state: + type: string + version: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: engines.longhorn.io +spec: + group: longhorn.io + names: + kind: Engine + listKind: EngineList + plural: engines + shortNames: + - lhe + singular: engine + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The current state of the engine + jsonPath: .status.currentState + name: State + type: string + - description: The node that the engine is on + jsonPath: .spec.nodeID + name: Node + type: string + - description: The instance manager of the engine + jsonPath: .status.instanceManagerName + name: InstanceManager + type: string + - description: The current image of the engine + jsonPath: .status.currentImage + name: Image + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: Engine is where Longhorn stores engine object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The data engine of the engine + jsonPath: .spec.dataEngine + name: Data Engine + type: string + - description: The current state of the engine + jsonPath: .status.currentState + name: State + type: string + - description: The node that the engine is on + jsonPath: .spec.nodeID + name: Node + type: string + - description: The instance manager of the engine + jsonPath: .status.instanceManagerName + name: InstanceManager + type: string + - description: The current image of the engine + jsonPath: .status.currentImage + name: Image + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: Engine is where Longhorn stores engine object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: EngineSpec defines the desired state of the Longhorn engine + properties: + active: + type: boolean + backendStoreDriver: + description: 'Deprecated: Replaced by field `dataEngine`.' + type: string + backupVolume: + type: string + dataEngine: + enum: + - v1 + - v2 + type: string + desireState: + type: string + disableFrontend: + type: boolean + engineImage: + description: 'Deprecated: Replaced by field `image`.' + type: string + frontend: + enum: + - blockdev + - iscsi + - nvmf + - "" + type: string + image: + type: string + logRequested: + type: boolean + nodeID: + type: string + replicaAddressMap: + additionalProperties: + type: string + type: object + requestedBackupRestore: + type: string + requestedDataSource: + type: string + revisionCounterDisabled: + type: boolean + salvageRequested: + type: boolean + snapshotMaxCount: + type: integer + snapshotMaxSize: + format: int64 + type: string + unmapMarkSnapChainRemovedEnabled: + type: boolean + upgradedReplicaAddressMap: + additionalProperties: + type: string + type: object + volumeName: + type: string + volumeSize: + format: int64 + type: string + type: object + status: + description: EngineStatus defines the observed state of the Longhorn engine + properties: + backupStatus: + additionalProperties: + properties: + backupURL: + type: string + error: + type: string + progress: + type: integer + replicaAddress: + type: string + snapshotName: + type: string + state: + type: string + type: object + nullable: true + type: object + cloneStatus: + additionalProperties: + properties: + error: + type: string + fromReplicaAddress: + type: string + isCloning: + type: boolean + progress: + type: integer + snapshotName: + type: string + state: + type: string + type: object + nullable: true + type: object + conditions: + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + currentImage: + type: string + currentReplicaAddressMap: + additionalProperties: + type: string + nullable: true + type: object + currentSize: + format: int64 + type: string + currentState: + type: string + endpoint: + type: string + instanceManagerName: + type: string + ip: + type: string + isExpanding: + type: boolean + lastExpansionError: + type: string + lastExpansionFailedAt: + type: string + lastRestoredBackup: + type: string + logFetched: + type: boolean + ownerID: + type: string + port: + type: integer + purgeStatus: + additionalProperties: + properties: + error: + type: string + isPurging: + type: boolean + progress: + type: integer + state: + type: string + type: object + nullable: true + type: object + rebuildStatus: + additionalProperties: + properties: + error: + type: string + fromReplicaAddress: + type: string + isRebuilding: + type: boolean + progress: + type: integer + state: + type: string + type: object + nullable: true + type: object + replicaModeMap: + additionalProperties: + type: string + nullable: true + type: object + restoreStatus: + additionalProperties: + properties: + backupURL: + type: string + currentRestoringBackup: + type: string + error: + type: string + filename: + type: string + isRestoring: + type: boolean + lastRestored: + type: string + progress: + type: integer + state: + type: string + type: object + nullable: true + type: object + salvageExecuted: + type: boolean + snapshotMaxCount: + type: integer + snapshotMaxSize: + format: int64 + type: string + snapshots: + additionalProperties: + properties: + children: + additionalProperties: + type: boolean + nullable: true + type: object + created: + type: string + labels: + additionalProperties: + type: string + nullable: true + type: object + name: + type: string + parent: + type: string + removed: + type: boolean + size: + type: string + usercreated: + type: boolean + type: object + nullable: true + type: object + snapshotsError: + type: string + started: + type: boolean + storageIP: + type: string + unmapMarkSnapChainRemovedEnabled: + type: boolean + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: instancemanagers.longhorn.io +spec: + group: longhorn.io + names: + kind: InstanceManager + listKind: InstanceManagerList + plural: instancemanagers + shortNames: + - lhim + singular: instancemanager + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The state of the instance manager + jsonPath: .status.currentState + name: State + type: string + - description: The type of the instance manager (engine or replica) + jsonPath: .spec.type + name: Type + type: string + - description: The node that the instance manager is running on + jsonPath: .spec.nodeID + name: Node + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: InstanceManager is where Longhorn stores instance manager object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The data engine of the instance manager + jsonPath: .spec.dataEngine + name: Data Engine + type: string + - description: The state of the instance manager + jsonPath: .status.currentState + name: State + type: string + - description: The type of the instance manager (engine or replica) + jsonPath: .spec.type + name: Type + type: string + - description: The node that the instance manager is running on + jsonPath: .spec.nodeID + name: Node + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: InstanceManager is where Longhorn stores instance manager object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: InstanceManagerSpec defines the desired state of the Longhorn instance manager + properties: + dataEngine: + type: string + image: + type: string + nodeID: + type: string + type: + enum: + - aio + - engine + - replica + type: string + type: object + status: + description: InstanceManagerStatus defines the observed state of the Longhorn instance manager + properties: + apiMinVersion: + type: integer + apiVersion: + type: integer + proxyApiMinVersion: + type: integer + proxyApiVersion: + type: integer + currentState: + type: string + instanceEngines: + additionalProperties: + properties: + spec: + properties: + backendStoreDriver: + description: 'Deprecated: Replaced by field `dataEngine`.' + type: string + dataEngine: + type: string + name: + type: string + type: object + status: + properties: + conditions: + additionalProperties: + type: boolean + type: object + endpoint: + type: string + errorMsg: + type: string + listen: + type: string + portEnd: + format: int32 + type: integer + portStart: + format: int32 + type: integer + resourceVersion: + format: int64 + type: integer + state: + type: string + type: + type: string + type: object + type: object + nullable: true + type: object + instanceReplicas: + additionalProperties: + properties: + spec: + properties: + backendStoreDriver: + description: 'Deprecated: Replaced by field `dataEngine`.' + type: string + dataEngine: + type: string + name: + type: string + type: object + status: + properties: + conditions: + additionalProperties: + type: boolean + type: object + endpoint: + type: string + errorMsg: + type: string + listen: + type: string + portEnd: + format: int32 + type: integer + portStart: + format: int32 + type: integer + resourceVersion: + format: int64 + type: integer + state: + type: string + type: + type: string + type: object + type: object + nullable: true + type: object + instances: + additionalProperties: + properties: + spec: + properties: + backendStoreDriver: + description: 'Deprecated: Replaced by field `dataEngine`.' + type: string + dataEngine: + type: string + name: + type: string + type: object + status: + properties: + conditions: + additionalProperties: + type: boolean + type: object + endpoint: + type: string + errorMsg: + type: string + listen: + type: string + portEnd: + format: int32 + type: integer + portStart: + format: int32 + type: integer + resourceVersion: + format: int64 + type: integer + state: + type: string + type: + type: string + type: object + type: object + nullable: true + description: 'Deprecated: Replaced by InstanceEngines and InstanceReplicas' + type: object + ip: + type: string + ownerID: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: nodes.longhorn.io +spec: + preserveUnknownFields: false + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: longhorn-conversion-webhook + namespace: longhorn-system + path: /v1/webhook/conversion + port: 9501 + conversionReviewVersions: + - v1beta2 + - v1beta1 + group: longhorn.io + names: + kind: Node + listKind: NodeList + plural: nodes + shortNames: + - lhn + singular: node + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Indicate whether the node is ready + jsonPath: .status.conditions['Ready']['status'] + name: Ready + type: string + - description: Indicate whether the user disabled/enabled replica scheduling for the node + jsonPath: .spec.allowScheduling + name: AllowScheduling + type: boolean + - description: Indicate whether Longhorn can schedule replicas on the node + jsonPath: .status.conditions['Schedulable']['status'] + name: Schedulable + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: Node is where Longhorn stores Longhorn node object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: Indicate whether the node is ready + jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - description: Indicate whether the user disabled/enabled replica scheduling for the node + jsonPath: .spec.allowScheduling + name: AllowScheduling + type: boolean + - description: Indicate whether Longhorn can schedule replicas on the node + jsonPath: .status.conditions[?(@.type=='Schedulable')].status + name: Schedulable + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: Node is where Longhorn stores Longhorn node object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: NodeSpec defines the desired state of the Longhorn node + properties: + allowScheduling: + description: Allow scheduling replicas on the node. + type: boolean + disks: + additionalProperties: + properties: + allowScheduling: + type: boolean + diskType: + enum: + - filesystem + - block + type: string + evictionRequested: + type: boolean + path: + type: string + storageReserved: + format: int64 + type: integer + tags: + items: + type: string + type: array + type: object + type: object + evictionRequested: + type: boolean + instanceManagerCPURequest: + type: integer + name: + type: string + tags: + items: + type: string + type: array + type: object + status: + description: NodeStatus defines the observed state of the Longhorn node + properties: + autoEvicting: + type: boolean + conditions: + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + diskStatus: + additionalProperties: + properties: + conditions: + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + diskType: + type: string + diskUUID: + type: string + filesystemType: + type: string + scheduledReplica: + additionalProperties: + format: int64 + type: integer + nullable: true + type: object + storageAvailable: + format: int64 + type: integer + storageMaximum: + format: int64 + type: integer + storageScheduled: + format: int64 + type: integer + type: object + description: The status of the disks on the node. + nullable: true + type: object + region: + description: The Region of the node. + type: string + snapshotCheckStatus: + description: The status of the snapshot integrity check. + properties: + lastPeriodicCheckedAt: + format: date-time + type: string + type: object + zone: + description: The Zone of the node. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: orphans.longhorn.io +spec: + group: longhorn.io + names: + kind: Orphan + listKind: OrphanList + plural: orphans + shortNames: + - lho + singular: orphan + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The type of the orphan + jsonPath: .spec.orphanType + name: Type + type: string + - description: The node that the orphan is on + jsonPath: .spec.nodeID + name: Node + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: Orphan is where Longhorn stores orphan object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OrphanSpec defines the desired state of the Longhorn orphaned data + properties: + nodeID: + description: The node ID on which the controller is responsible to reconcile this orphan CR. + type: string + orphanType: + description: The type of the orphaned data. Can be "replica". + type: string + parameters: + additionalProperties: + type: string + description: The parameters of the orphaned data + type: object + type: object + status: + description: OrphanStatus defines the observed state of the Longhorn orphaned data + properties: + conditions: + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + ownerID: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + longhorn-manager: "" + name: recurringjobs.longhorn.io +spec: + group: longhorn.io + names: + kind: RecurringJob + listKind: RecurringJobList + plural: recurringjobs + shortNames: + - lhrj + singular: recurringjob + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Sets groupings to the jobs. When set to "default" group will be added to the volume label when no other job label exist in volume + jsonPath: .spec.groups + name: Groups + type: string + - description: Should be one of "backup" or "snapshot" + jsonPath: .spec.task + name: Task + type: string + - description: The cron expression represents recurring job scheduling + jsonPath: .spec.cron + name: Cron + type: string + - description: The number of snapshots/backups to keep for the volume + jsonPath: .spec.retain + name: Retain + type: integer + - description: The concurrent job to run by each cron job + jsonPath: .spec.concurrency + name: Concurrency + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Specify the labels + jsonPath: .spec.labels + name: Labels + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: RecurringJob is where Longhorn stores recurring job object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: Sets groupings to the jobs. When set to "default" group will be added to the volume label when no other job label exist in volume + jsonPath: .spec.groups + name: Groups + type: string + - description: Should be one of "snapshot", "snapshot-force-create", "snapshot-cleanup", "snapshot-delete", "backup", "backup-force-create" or "filesystem-trim" + jsonPath: .spec.task + name: Task + type: string + - description: The cron expression represents recurring job scheduling + jsonPath: .spec.cron + name: Cron + type: string + - description: The number of snapshots/backups to keep for the volume + jsonPath: .spec.retain + name: Retain + type: integer + - description: The concurrent job to run by each cron job + jsonPath: .spec.concurrency + name: Concurrency + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Specify the labels + jsonPath: .spec.labels + name: Labels + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: RecurringJob is where Longhorn stores recurring job object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: RecurringJobSpec defines the desired state of the Longhorn recurring job + properties: + concurrency: + description: The concurrency of taking the snapshot/backup. + type: integer + cron: + description: The cron setting. + type: string + groups: + description: The recurring job group. + items: + type: string + type: array + labels: + additionalProperties: + type: string + description: The label of the snapshot/backup. + type: object + name: + description: The recurring job name. + type: string + retain: + description: The retain count of the snapshot/backup. + type: integer + task: + description: The recurring job task. Can be "snapshot", "snapshot-force-create", "snapshot-cleanup", "snapshot-delete", "backup", "backup-force-create" or "filesystem-trim" + enum: + - snapshot + - snapshot-force-create + - snapshot-cleanup + - snapshot-delete + - backup + - backup-force-create + - filesystem-trim + type: string + type: object + status: + description: RecurringJobStatus defines the observed state of the Longhorn recurring job + properties: + ownerID: + description: The owner ID which is responsible to reconcile this recurring job CR. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: replicas.longhorn.io +spec: + group: longhorn.io + names: + kind: Replica + listKind: ReplicaList + plural: replicas + shortNames: + - lhr + singular: replica + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The current state of the replica + jsonPath: .status.currentState + name: State + type: string + - description: The node that the replica is on + jsonPath: .spec.nodeID + name: Node + type: string + - description: The disk that the replica is on + jsonPath: .spec.diskID + name: Disk + type: string + - description: The instance manager of the replica + jsonPath: .status.instanceManagerName + name: InstanceManager + type: string + - description: The current image of the replica + jsonPath: .status.currentImage + name: Image + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: Replica is where Longhorn stores replica object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The data engine of the replica + jsonPath: .spec.dataEngine + name: Data Engine + type: string + - description: The current state of the replica + jsonPath: .status.currentState + name: State + type: string + - description: The node that the replica is on + jsonPath: .spec.nodeID + name: Node + type: string + - description: The disk that the replica is on + jsonPath: .spec.diskID + name: Disk + type: string + - description: The instance manager of the replica + jsonPath: .status.instanceManagerName + name: InstanceManager + type: string + - description: The current image of the replica + jsonPath: .status.currentImage + name: Image + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: Replica is where Longhorn stores replica object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ReplicaSpec defines the desired state of the Longhorn replica + properties: + active: + type: boolean + backendStoreDriver: + description: 'Deprecated: Replaced by field `dataEngine`.' + type: string + backingImage: + type: string + dataDirectoryName: + type: string + dataEngine: + enum: + - v1 + - v2 + type: string + desireState: + type: string + diskID: + type: string + diskPath: + type: string + engineImage: + description: 'Deprecated: Replaced by field `image`.' + type: string + engineName: + type: string + evictionRequested: + type: boolean + failedAt: + type: string + hardNodeAffinity: + type: string + healthyAt: + type: string + image: + type: string + logRequested: + type: boolean + nodeID: + type: string + rebuildRetryCount: + type: integer + revisionCounterDisabled: + type: boolean + salvageRequested: + type: boolean + snapshotMaxCount: + type: integer + snapshotMaxSize: + format: int64 + type: string + unmapMarkDiskChainRemovedEnabled: + type: boolean + volumeName: + type: string + volumeSize: + format: int64 + type: string + type: object + status: + description: ReplicaStatus defines the observed state of the Longhorn replica + properties: + conditions: + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + currentImage: + type: string + currentState: + type: string + evictionRequested: + description: 'Deprecated: Replaced by field `spec.evictionRequested`.' + type: boolean + instanceManagerName: + type: string + ip: + type: string + logFetched: + type: boolean + ownerID: + type: string + port: + type: integer + salvageExecuted: + type: boolean + started: + type: boolean + storageIP: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: settings.longhorn.io +spec: + group: longhorn.io + names: + kind: Setting + listKind: SettingList + plural: settings + shortNames: + - lhs + singular: setting + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The value of the setting + jsonPath: .value + name: Value + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: Setting is where Longhorn stores setting object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + value: + type: string + required: + - value + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The value of the setting + jsonPath: .value + name: Value + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: Setting is where Longhorn stores setting object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + value: + description: The value of the setting. + type: string + required: + - value + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: sharemanagers.longhorn.io +spec: + group: longhorn.io + names: + kind: ShareManager + listKind: ShareManagerList + plural: sharemanagers + shortNames: + - lhsm + singular: sharemanager + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The state of the share manager + jsonPath: .status.state + name: State + type: string + - description: The node that the share manager is owned by + jsonPath: .status.ownerID + name: Node + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: ShareManager is where Longhorn stores share manager object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The state of the share manager + jsonPath: .status.state + name: State + type: string + - description: The node that the share manager is owned by + jsonPath: .status.ownerID + name: Node + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: ShareManager is where Longhorn stores share manager object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ShareManagerSpec defines the desired state of the Longhorn share manager + properties: + image: + description: Share manager image used for creating a share manager pod + type: string + type: object + status: + description: ShareManagerStatus defines the observed state of the Longhorn share manager + properties: + endpoint: + description: NFS endpoint that can access the mounted filesystem of the volume + type: string + ownerID: + description: The node ID on which the controller is responsible to reconcile this share manager resource + type: string + state: + description: The state of the share manager resource + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: snapshots.longhorn.io +spec: + group: longhorn.io + names: + kind: Snapshot + listKind: SnapshotList + plural: snapshots + shortNames: + - lhsnap + singular: snapshot + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The volume that this snapshot belongs to + jsonPath: .spec.volume + name: Volume + type: string + - description: Timestamp when the point-in-time snapshot was taken + jsonPath: .status.creationTime + name: CreationTime + type: string + - description: Indicates if the snapshot is ready to be used to restore/backup a volume + jsonPath: .status.readyToUse + name: ReadyToUse + type: boolean + - description: Represents the minimum size of volume required to rehydrate from this snapshot + jsonPath: .status.restoreSize + name: RestoreSize + type: string + - description: The actual size of the snapshot + jsonPath: .status.size + name: Size + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: Snapshot is the Schema for the snapshots API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: SnapshotSpec defines the desired state of Longhorn Snapshot + properties: + createSnapshot: + description: require creating a new snapshot + type: boolean + labels: + additionalProperties: + type: string + description: The labels of snapshot + nullable: true + type: object + volume: + description: the volume that this snapshot belongs to. This field is immutable after creation. Required + type: string + required: + - volume + type: object + status: + description: SnapshotStatus defines the observed state of Longhorn Snapshot + properties: + checksum: + type: string + children: + additionalProperties: + type: boolean + nullable: true + type: object + creationTime: + type: string + error: + type: string + labels: + additionalProperties: + type: string + nullable: true + type: object + markRemoved: + type: boolean + ownerID: + type: string + parent: + type: string + readyToUse: + type: boolean + restoreSize: + format: int64 + type: integer + size: + format: int64 + type: integer + userCreated: + type: boolean + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: supportbundles.longhorn.io +spec: + group: longhorn.io + names: + kind: SupportBundle + listKind: SupportBundleList + plural: supportbundles + shortNames: + - lhbundle + singular: supportbundle + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The state of the support bundle + jsonPath: .status.state + name: State + type: string + - description: The issue URL + jsonPath: .spec.issueURL + name: Issue + type: string + - description: A brief description of the issue + jsonPath: .spec.description + name: Description + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: SupportBundle is where Longhorn stores support bundle object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: SupportBundleSpec defines the desired state of the Longhorn SupportBundle + properties: + description: + description: A brief description of the issue + type: string + issueURL: + description: The issue URL + nullable: true + type: string + nodeID: + description: The preferred responsible controller node ID. + type: string + required: + - description + type: object + status: + description: SupportBundleStatus defines the observed state of the Longhorn SupportBundle + properties: + conditions: + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + type: array + filename: + type: string + filesize: + format: int64 + type: integer + image: + description: The support bundle manager image + type: string + managerIP: + description: The support bundle manager IP + type: string + ownerID: + description: The current responsible controller node ID + type: string + progress: + type: integer + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: systembackups.longhorn.io +spec: + group: longhorn.io + names: + kind: SystemBackup + listKind: SystemBackupList + plural: systembackups + shortNames: + - lhsb + singular: systembackup + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The system backup Longhorn version + jsonPath: .status.version + name: Version + type: string + - description: The system backup state + jsonPath: .status.state + name: State + type: string + - description: The system backup creation time + jsonPath: .status.createdAt + name: Created + type: string + - description: The last time that the system backup was synced into the cluster + jsonPath: .status.lastSyncedAt + name: LastSyncedAt + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: SystemBackup is where Longhorn stores system backup object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: SystemBackupSpec defines the desired state of the Longhorn SystemBackup + properties: + volumeBackupPolicy: + description: The create volume backup policy Can be "if-not-present", "always" or "disabled" + nullable: true + type: string + type: object + status: + description: SystemBackupStatus defines the observed state of the Longhorn SystemBackup + properties: + conditions: + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + createdAt: + description: The system backup creation time. + format: date-time + type: string + gitCommit: + description: The saved Longhorn manager git commit. + nullable: true + type: string + lastSyncedAt: + description: The last time that the system backup was synced into the cluster. + format: date-time + nullable: true + type: string + managerImage: + description: The saved manager image. + type: string + ownerID: + description: The node ID of the responsible controller to reconcile this SystemBackup. + type: string + state: + description: The system backup state. + type: string + version: + description: The saved Longhorn version. + nullable: true + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: systemrestores.longhorn.io +spec: + group: longhorn.io + names: + kind: SystemRestore + listKind: SystemRestoreList + plural: systemrestores + shortNames: + - lhsr + singular: systemrestore + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The system restore state + jsonPath: .status.state + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: SystemRestore is where Longhorn stores system restore object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: SystemRestoreSpec defines the desired state of the Longhorn SystemRestore + properties: + systemBackup: + description: The system backup name in the object store. + type: string + required: + - systemBackup + type: object + status: + description: SystemRestoreStatus defines the observed state of the Longhorn SystemRestore + properties: + conditions: + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + ownerID: + description: The node ID of the responsible controller to reconcile this SystemRestore. + type: string + sourceURL: + description: The source system backup URL. + type: string + state: + description: The system restore state. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: volumes.longhorn.io +spec: + preserveUnknownFields: false + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: longhorn-conversion-webhook + namespace: longhorn-system + path: /v1/webhook/conversion + port: 9501 + conversionReviewVersions: + - v1beta2 + - v1beta1 + group: longhorn.io + names: + kind: Volume + listKind: VolumeList + plural: volumes + shortNames: + - lhv + singular: volume + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The state of the volume + jsonPath: .status.state + name: State + type: string + - description: The robustness of the volume + jsonPath: .status.robustness + name: Robustness + type: string + - description: The scheduled condition of the volume + jsonPath: .status.conditions['scheduled']['status'] + name: Scheduled + type: string + - description: The size of the volume + jsonPath: .spec.size + name: Size + type: string + - description: The node that the volume is currently attaching to + jsonPath: .status.currentNodeID + name: Node + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: Volume is where Longhorn stores volume object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + x-kubernetes-preserve-unknown-fields: true + status: + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - description: The data engine of the volume + jsonPath: .spec.dataEngine + name: Data Engine + type: string + - description: The state of the volume + jsonPath: .status.state + name: State + type: string + - description: The robustness of the volume + jsonPath: .status.robustness + name: Robustness + type: string + - description: The scheduled condition of the volume + jsonPath: .status.conditions[?(@.type=='Schedulable')].status + name: Scheduled + type: string + - description: The size of the volume + jsonPath: .spec.size + name: Size + type: string + - description: The node that the volume is currently attaching to + jsonPath: .status.currentNodeID + name: Node + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: Volume is where Longhorn stores volume object. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VolumeSpec defines the desired state of the Longhorn volume + properties: + Standby: + type: boolean + accessMode: + enum: + - rwo + - rwx + type: string + backendStoreDriver: + description: 'Deprecated: Replaced by field `dataEngine`.' + type: string + backingImage: + type: string + backupCompressionMethod: + enum: + - none + - lz4 + - gzip + type: string + dataEngine: + enum: + - v1 + - v2 + type: string + dataLocality: + enum: + - disabled + - best-effort + - strict-local + type: string + dataSource: + type: string + disableFrontend: + type: boolean + diskSelector: + items: + type: string + type: array + encrypted: + type: boolean + engineImage: + description: 'Deprecated: Replaced by field `image`.' + type: string + fromBackup: + type: string + frontend: + enum: + - blockdev + - iscsi + - nvmf + - "" + type: string + image: + type: string + lastAttachedBy: + type: string + migratable: + type: boolean + migrationNodeID: + type: string + nodeID: + type: string + nodeSelector: + items: + type: string + type: array + numberOfReplicas: + type: integer + offlineReplicaRebuilding: + description: OfflineReplicaRebuilding is used to determine if the offline replica rebuilding feature is enabled or not + enum: + - ignored + - disabled + - enabled + type: string + replicaAutoBalance: + enum: + - ignored + - disabled + - least-effort + - best-effort + type: string + replicaDiskSoftAntiAffinity: + description: Replica disk soft anti affinity of the volume. Set enabled to allow replicas to be scheduled in the same disk. + enum: + - ignored + - enabled + - disabled + type: string + replicaSoftAntiAffinity: + description: Replica soft anti affinity of the volume. Set enabled to allow replicas to be scheduled on the same node. + enum: + - ignored + - enabled + - disabled + type: string + replicaZoneSoftAntiAffinity: + description: Replica zone soft anti affinity of the volume. Set enabled to allow replicas to be scheduled in the same zone. + enum: + - ignored + - enabled + - disabled + type: string + restoreVolumeRecurringJob: + enum: + - ignored + - enabled + - disabled + type: string + revisionCounterDisabled: + type: boolean + size: + format: int64 + type: string + snapshotDataIntegrity: + enum: + - ignored + - disabled + - enabled + - fast-check + type: string + snapshotMaxCount: + type: integer + snapshotMaxSize: + format: int64 + type: string + staleReplicaTimeout: + type: integer + unmapMarkSnapChainRemoved: + enum: + - ignored + - disabled + - enabled + type: string + type: object + status: + description: VolumeStatus defines the observed state of the Longhorn volume + properties: + actualSize: + format: int64 + type: integer + cloneStatus: + properties: + snapshot: + type: string + sourceVolume: + type: string + state: + type: string + type: object + conditions: + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + currentImage: + type: string + currentMigrationNodeID: + description: the node that this volume is currently migrating to + type: string + currentNodeID: + type: string + expansionRequired: + type: boolean + frontendDisabled: + type: boolean + isStandby: + type: boolean + kubernetesStatus: + properties: + lastPVCRefAt: + type: string + lastPodRefAt: + type: string + namespace: + description: determine if PVC/Namespace is history or not + type: string + pvName: + type: string + pvStatus: + type: string + pvcName: + type: string + workloadsStatus: + description: determine if Pod/Workload is history or not + items: + properties: + podName: + type: string + podStatus: + type: string + workloadName: + type: string + workloadType: + type: string + type: object + nullable: true + type: array + type: object + lastBackup: + type: string + lastBackupAt: + type: string + lastDegradedAt: + type: string + offlineReplicaRebuildingRequired: + type: boolean + ownerID: + type: string + pendingNodeID: + description: Deprecated. + type: string + remountRequestedAt: + type: string + restoreInitiated: + type: boolean + restoreRequired: + type: boolean + robustness: + type: string + shareEndpoint: + type: string + shareState: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/crds.yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + longhorn-manager: "" + name: volumeattachments.longhorn.io +spec: + group: longhorn.io + names: + kind: VolumeAttachment + listKind: VolumeAttachmentList + plural: volumeattachments + shortNames: + - lhva + singular: volumeattachment + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + description: VolumeAttachment stores attachment information of a Longhorn volume + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VolumeAttachmentSpec defines the desired state of Longhorn VolumeAttachment + properties: + attachmentTickets: + additionalProperties: + properties: + generation: + description: A sequence number representing a specific generation of the desired state. Populated by the system. Read-only. + format: int64 + type: integer + id: + description: The unique ID of this attachment. Used to differentiate different attachments of the same volume. + type: string + nodeID: + description: The node that this attachment is requesting + type: string + parameters: + additionalProperties: + type: string + description: Optional additional parameter for this attachment + type: object + type: + type: string + type: object + type: object + volume: + description: The name of Longhorn volume of this VolumeAttachment + type: string + required: + - volume + type: object + status: + description: VolumeAttachmentStatus defines the observed state of Longhorn VolumeAttachment + properties: + attachmentTicketStatuses: + additionalProperties: + properties: + conditions: + description: Record any error when trying to fulfill this attachment + items: + properties: + lastProbeTime: + description: Last time we probed the condition. + type: string + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + message: + description: Human-readable message indicating details about last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition. Can be True, False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + nullable: true + type: array + generation: + description: A sequence number representing a specific generation of the desired state. Populated by the system. Read-only. + format: int64 + type: integer + id: + description: The unique ID of this attachment. Used to differentiate different attachments of the same volume. + type: string + satisfied: + description: Indicate whether this attachment ticket has been satisfied + type: boolean + required: + - conditions + - satisfied + type: object + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +# Source: longhorn/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: longhorn-role + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 +rules: +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - "*" +- apiGroups: [""] + resources: ["pods", "events", "persistentvolumes", "persistentvolumeclaims","persistentvolumeclaims/status", "nodes", "proxy/nodes", "pods/log", "secrets", "services", "endpoints", "configmaps", "serviceaccounts"] + verbs: ["*"] +- apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "list"] +- apiGroups: ["apps"] + resources: ["daemonsets", "statefulsets", "deployments"] + verbs: ["*"] +- apiGroups: ["batch"] + resources: ["jobs", "cronjobs"] + verbs: ["*"] +- apiGroups: ["policy"] + resources: ["poddisruptionbudgets", "podsecuritypolicies"] + verbs: ["*"] +- apiGroups: ["scheduling.k8s.io"] + resources: ["priorityclasses"] + verbs: ["watch", "list"] +- apiGroups: ["storage.k8s.io"] + resources: ["storageclasses", "volumeattachments", "volumeattachments/status", "csinodes", "csidrivers"] + verbs: ["*"] +- apiGroups: ["snapshot.storage.k8s.io"] + resources: ["volumesnapshotclasses", "volumesnapshots", "volumesnapshotcontents", "volumesnapshotcontents/status"] + verbs: ["*"] +- apiGroups: ["longhorn.io"] + resources: ["volumes", "volumes/status", "engines", "engines/status", "replicas", "replicas/status", "settings", + "engineimages", "engineimages/status", "nodes", "nodes/status", "instancemanagers", "instancemanagers/status", + "sharemanagers", "sharemanagers/status", "backingimages", "backingimages/status", + "backingimagemanagers", "backingimagemanagers/status", "backingimagedatasources", "backingimagedatasources/status", + "backuptargets", "backuptargets/status", "backupvolumes", "backupvolumes/status", "backups", "backups/status", + "recurringjobs", "recurringjobs/status", "orphans", "orphans/status", "snapshots", "snapshots/status", + "supportbundles", "supportbundles/status", "systembackups", "systembackups/status", "systemrestores", "systemrestores/status", + "volumeattachments", "volumeattachments/status", "backupbackingimages", "backupbackingimages/status"] + verbs: ["*"] +- apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["*"] +- apiGroups: ["metrics.k8s.io"] + resources: ["pods", "nodes"] + verbs: ["get", "list"] +- apiGroups: ["apiregistration.k8s.io"] + resources: ["apiservices"] + verbs: ["list", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"] + verbs: ["get", "list", "create", "patch", "delete"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["roles", "rolebindings", "clusterrolebindings", "clusterroles"] + verbs: ["*"] +--- +# Source: longhorn/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: longhorn-bind + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: longhorn-role +subjects: +- kind: ServiceAccount + name: longhorn-service-account + namespace: longhorn-system +--- +# Source: longhorn/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: longhorn-support-bundle + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: +- kind: ServiceAccount + name: longhorn-support-bundle + namespace: longhorn-system +--- +# Source: longhorn/templates/daemonset-sa.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + app: longhorn-manager + name: longhorn-backend + namespace: longhorn-system +spec: + type: ClusterIP + selector: + app: longhorn-manager + ports: + - name: manager + port: 9500 + targetPort: manager +--- +# Source: longhorn/templates/deployment-ui.yaml +kind: Service +apiVersion: v1 +metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + app: longhorn-ui + name: longhorn-frontend + namespace: longhorn-system +spec: + type: LoadBalancer + selector: + app: longhorn-ui + ports: + - name: http + port: 8888 + targetPort: http + nodePort: null +--- +# Source: longhorn/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + app: longhorn-conversion-webhook + name: longhorn-conversion-webhook + namespace: longhorn-system +spec: + type: ClusterIP + selector: + app: longhorn-manager + ports: + - name: conversion-webhook + port: 9501 + targetPort: conversion-wh +--- +# Source: longhorn/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + app: longhorn-admission-webhook + name: longhorn-admission-webhook + namespace: longhorn-system +spec: + type: ClusterIP + selector: + app: longhorn-manager + ports: + - name: admission-webhook + port: 9502 + targetPort: admission-wh +--- +# Source: longhorn/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + app: longhorn-recovery-backend + name: longhorn-recovery-backend + namespace: longhorn-system +spec: + type: ClusterIP + selector: + app: longhorn-manager + ports: + - name: recovery-backend + port: 9503 + targetPort: recov-backend +--- +# Source: longhorn/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + name: longhorn-engine-manager + namespace: longhorn-system +spec: + clusterIP: None + selector: + longhorn.io/component: instance-manager + longhorn.io/instance-manager-type: engine +--- +# Source: longhorn/templates/services.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + name: longhorn-replica-manager + namespace: longhorn-system +spec: + clusterIP: None + selector: + longhorn.io/component: instance-manager + longhorn.io/instance-manager-type: replica +--- +# Source: longhorn/templates/daemonset-sa.yaml +apiVersion: apps/v1 +kind: DaemonSet +metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + app: longhorn-manager + name: longhorn-manager + namespace: longhorn-system +spec: + selector: + matchLabels: + app: longhorn-manager + template: + metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + app: longhorn-manager + spec: + containers: + - name: longhorn-manager + image: longhornio/longhorn-manager:v1.6.0 + imagePullPolicy: IfNotPresent + securityContext: + privileged: true + command: + - longhorn-manager + - -d + - daemon + - --engine-image + - "longhornio/longhorn-engine:v1.6.0" + - --instance-manager-image + - "longhornio/longhorn-instance-manager:v1.6.0" + - --share-manager-image + - "longhornio/longhorn-share-manager:v1.6.0" + - --backing-image-manager-image + - "longhornio/backing-image-manager:v1.6.0" + - --support-bundle-manager-image + - "longhornio/support-bundle-kit:v0.0.33" + - --manager-image + - "longhornio/longhorn-manager:v1.6.0" + - --service-account + - longhorn-service-account + - --upgrade-version-check + ports: + - containerPort: 9500 + name: manager + - containerPort: 9501 + name: conversion-wh + - containerPort: 9502 + name: admission-wh + - containerPort: 9503 + name: recov-backend + readinessProbe: + httpGet: + path: /v1/healthz + port: 9501 + scheme: HTTPS + volumeMounts: + - name: dev + mountPath: /host/dev/ + - name: proc + mountPath: /host/proc/ + - name: longhorn + mountPath: /var/lib/longhorn/ + mountPropagation: Bidirectional + - name: longhorn-grpc-tls + mountPath: /tls-files/ + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + volumes: + - name: dev + hostPath: + path: /dev/ + - name: proc + hostPath: + path: /proc/ + - name: longhorn + hostPath: + path: /var/lib/longhorn/ + - name: longhorn-grpc-tls + secret: + secretName: longhorn-grpc-tls + optional: true + priorityClassName: "longhorn-critical" + serviceAccountName: longhorn-service-account + updateStrategy: + rollingUpdate: + maxUnavailable: "100%" +--- +# Source: longhorn/templates/deployment-driver.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: longhorn-driver-deployer + namespace: longhorn-system + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 +spec: + replicas: 1 + selector: + matchLabels: + app: longhorn-driver-deployer + template: + metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + app: longhorn-driver-deployer + spec: + initContainers: + - name: wait-longhorn-manager + image: longhornio/longhorn-manager:v1.6.0 + command: ['sh', '-c', 'while [ $(curl -m 1 -s -o /dev/null -w "%{http_code}" http://longhorn-backend:9500/v1) != "200" ]; do echo waiting; sleep 2; done'] + containers: + - name: longhorn-driver-deployer + image: longhornio/longhorn-manager:v1.6.0 + imagePullPolicy: IfNotPresent + command: + - longhorn-manager + - -d + - deploy-driver + - --manager-image + - "longhornio/longhorn-manager:v1.6.0" + - --manager-url + - http://longhorn-backend:9500/v1 + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: CSI_ATTACHER_IMAGE + value: "longhornio/csi-attacher:v4.4.2" + - name: CSI_PROVISIONER_IMAGE + value: "longhornio/csi-provisioner:v3.6.2" + - name: CSI_NODE_DRIVER_REGISTRAR_IMAGE + value: "longhornio/csi-node-driver-registrar:v2.9.2" + - name: CSI_RESIZER_IMAGE + value: "longhornio/csi-resizer:v1.9.2" + - name: CSI_SNAPSHOTTER_IMAGE + value: "longhornio/csi-snapshotter:v6.3.2" + - name: CSI_LIVENESS_PROBE_IMAGE + value: "longhornio/livenessprobe:v2.11.0" + priorityClassName: "longhorn-critical" + serviceAccountName: longhorn-service-account + securityContext: + runAsUser: 0 +--- +# Source: longhorn/templates/deployment-ui.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + app: longhorn-ui + name: longhorn-ui + namespace: longhorn-system +spec: + replicas: 2 + selector: + matchLabels: + app: longhorn-ui + template: + metadata: + labels: + app.kubernetes.io/name: longhorn + app.kubernetes.io/instance: longhorn + app.kubernetes.io/version: v1.6.0 + app: longhorn-ui + spec: + serviceAccountName: longhorn-ui-service-account + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - longhorn-ui + topologyKey: kubernetes.io/hostname + containers: + - name: longhorn-ui + image: longhornio/longhorn-ui:v1.6.0 + imagePullPolicy: IfNotPresent + volumeMounts: + - name : nginx-cache + mountPath: /var/cache/nginx/ + - name : nginx-config + mountPath: /var/config/nginx/ + - name: var-run + mountPath: /var/run/ + ports: + - containerPort: 8000 + name: http + env: + - name: LONGHORN_MANAGER_IP + value: "http://longhorn-backend:9500" + - name: LONGHORN_UI_PORT + value: "8000" + volumes: + - emptyDir: {} + name: nginx-cache + - emptyDir: {} + name: nginx-config + - emptyDir: {} + name: var-run + priorityClassName: "longhorn-critical" +--- +# Source: longhorn/templates/validate-psp-install.yaml +# \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/kubernetes/K3s/welcomeK3s.sh b/azure_jumpstart_ag/artifacts/kubernetes/K3s/welcomeK3s.sh new file mode 100644 index 0000000000..6e440b507b --- /dev/null +++ b/azure_jumpstart_ag/artifacts/kubernetes/K3s/welcomeK3s.sh @@ -0,0 +1,9 @@ +tput setaf 1;echo "-----------------------------------------------------------------------------------------------------------------------------" +echo "" +tput setaf 6;echo "Welcome to Jumpstart ArcBox Rancher K3s Kubernetes cluster management virtual machine!" +echo "" +tput setaf 6;echo "* To check the Rancher K3s deployment log, use the 'cat jumpstart_logs/installK3s.log' command." +echo "" +tput setaf 6;echo "* To work with Rancher K3s workload Kubernetes cluster, use the 'kubectl '. For example: kubectl get nodes" +echo "" +tput setaf 1;echo "-----------------------------------------------------------------------------------------------------------------------------" \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/monitoring/grafana-app-pods.json b/azure_jumpstart_ag/artifacts/monitoring/grafana-app-pods.json new file mode 100644 index 0000000000..f6c9139d65 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/monitoring/grafana-app-pods.json @@ -0,0 +1,2396 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 23, + "links": [], + "panels": [ + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 17, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "CPU Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 1 + }, + "hiddenSeries": false, + "id": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "requests", + "color": "#F2495C", + "fill": 0, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + }, + { + "alias": "limits", + "color": "#FF9830", + "fill": 0, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "time_series", + "legendFormat": "{{container}}", + "refId": "A" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", namespace=\"$namespace\", pod=\"$pod\", resource=\"cpu\"}\r\n)\r\n", + "format": "time_series", + "legendFormat": "requests", + "refId": "B" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", namespace=\"$namespace\", pod=\"$pod\", resource=\"cpu\"}\r\n)\r\n", + "format": "time_series", + "legendFormat": "limits", + "refId": "C" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "CPU Usage", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 18, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "CPU Throttling", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(increase(container_cpu_cfs_throttled_periods_total{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\"}[$__rate_interval])) by (container) /sum(increase(container_cpu_cfs_periods_total{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\"}[$__rate_interval])) by (container)", + "format": "time_series", + "legendFormat": "{{container}}", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0.25, + "yaxis": "left" + } + ], + "timeRegions": [], + "title": "CPU Throttling", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "logBase": 1, + "max": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 19, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "CPU Quota", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "columns": [], + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fontSize": "100%", + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "CPU Usage", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests %", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "CPU Limits", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Limits %", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Container", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "container", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "A" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "B" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "C" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "D" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "E" + } + ], + "thresholds": [], + "title": "CPU Quota", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table-old", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ] + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 20, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Memory Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 25 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "requests", + "color": "#F2495C", + "dashes": true, + "fill": 0, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + }, + { + "alias": "limits", + "color": "#FF9830", + "dashes": true, + "fill": 0, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", image!=\"\"}) by (container)", + "format": "time_series", + "legendFormat": "{{container}}", + "refId": "A" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", namespace=\"$namespace\", pod=\"$pod\", resource=\"memory\"}\r\n)\r\n", + "format": "time_series", + "legendFormat": "requests", + "refId": "B" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", namespace=\"$namespace\", pod=\"$pod\", resource=\"memory\"}\r\n)\r\n", + "format": "time_series", + "legendFormat": "limits", + "refId": "C" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Memory Usage (WSS)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 21, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Memory Quota", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "columns": [], + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fontSize": "100%", + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 33 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Memory Usage (WSS)", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests %", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Limits", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Limits %", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Usage (RSS)", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Usage (Cache)", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #G", + "thresholds": [], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Usage (Swap)", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #H", + "thresholds": [], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Container", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "container", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", image!=\"\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "A" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "B" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\", image!=\"\"}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "C" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "D" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", image!=\"\"}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "E" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(container_memory_rss{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\", container != \"\", container != \"POD\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "F" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(container_memory_cache{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\", container != \"\", container != \"POD\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "G" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(container_memory_swap{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\", container != \"\", container != \"POD\"}) by (container)", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "H" + } + ], + "thresholds": [], + "title": "Memory Quota", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table-old", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ] + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 22, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Bandwidth", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 41 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(irate(container_network_receive_bytes_total{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Receive Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 41 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Transmit Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 23, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Rate of Packets", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 49 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(irate(container_network_receive_packets_total{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Rate of Received Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 49 + }, + "hiddenSeries": false, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(irate(container_network_transmit_packets_total{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 56 + }, + "id": 24, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Rate of Packets Dropped", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 57 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 57 + }, + "hiddenSeries": false, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 64 + }, + "id": 25, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Storage IO - Distribution(Pod - Read & Writes)", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "decimals": -1, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 65 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "ceil(sum by(pod) (rate(container_fs_reads_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])))", + "format": "time_series", + "legendFormat": "Reads", + "refId": "A" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "ceil(sum by(pod) (rate(container_fs_writes_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\",namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])))", + "format": "time_series", + "legendFormat": "Writes", + "refId": "B" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "IOPS", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 65 + }, + "hiddenSeries": false, + "id": 13, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum by(pod) (rate(container_fs_reads_bytes_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "time_series", + "legendFormat": "Reads", + "refId": "A" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum by(pod) (rate(container_fs_writes_bytes_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "time_series", + "legendFormat": "Writes", + "refId": "B" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "ThroughPut", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 72 + }, + "id": 26, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Storage IO - Distribution(Containers)", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "decimals": -1, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 73 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "ceil(sum by(container) (rate(container_fs_reads_total{job=\"kubelet\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])))", + "format": "time_series", + "legendFormat": "{{container}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "IOPS(Reads+Writes)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 10, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 73 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.4.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum by(container) (rate(container_fs_reads_bytes_total{job=\"kubelet\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "time_series", + "legendFormat": "{{container}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "ThroughPut(Read+Write)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 80 + }, + "id": 27, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Storage IO - Distribution", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 81 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "sort": { + "col": 4, + "desc": true + }, + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "IOPS(Reads)", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "IOPS(Writes)", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "IOPS(Reads + Writes)", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Throughput(Read)", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Throughput(Write)", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Throughput(Read + Write)", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Container", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "container", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "align": "auto", + "colors": [], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum by(container) (rate(container_fs_reads_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "A" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum by(container) (rate(container_fs_writes_total{job=\"kubelet\",device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "B" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum by(container) (rate(container_fs_reads_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "C" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum by(container) (rate(container_fs_reads_bytes_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "D" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum by(container) (rate(container_fs_writes_bytes_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "E" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum by(container) (rate(container_fs_reads_bytes_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", device=~\"mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+\", container!=\"\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "F" + } + ], + "thresholds": [], + "title": "Current Storage IO", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table-old", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ] + } + ], + "schemaVersion": 39, + "tags": [ + "workloads", + "pods" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "chicago", + "value": "fe0ylwo898wlcb" + }, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": { + "selected": false, + "text": "azure-arc", + "value": "azure-arc" + }, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(kube_namespace_status_phase{job=\"kube-state-metrics\", namespace=~\".*contoso.*\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "cluster-metadata-operator-dfb9f4b7f-wvvhj", + "value": "cluster-metadata-operator-dfb9f4b7f-wvvhj" + }, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "pod", + "options": [], + "query": "label_values(kube_pod_info{job=\"kube-state-metrics\", namespace=\"$namespace\"}, pod)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Kubernetes / Workload / Pod", + "uid": "9701f5d6-af2d-442b-a2a4-d4d05f9b79b1", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/monitoring/grafana-app-store-asset.json b/azure_jumpstart_ag/artifacts/monitoring/grafana-app-store-asset.json new file mode 100644 index 0000000000..21ddf5ccd5 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/monitoring/grafana-app-store-asset.json @@ -0,0 +1,997 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 5, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 21, + "panels": [], + "title": "Lighting", + "type": "row" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0": { + "color": "red", + "index": 0, + "text": "Off" + }, + "1": { + "color": "yellow", + "index": 1, + "text": "On" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "yellow", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 1 + }, + "id": 12, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "lighting_status ", + "format": "time_series", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "{{device_id}}", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "Lighting Status", + "type": "bargauge" + }, + { + "datasource": { + "name": "${datasource}", + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "lumens" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 9, + "x": 7, + "y": 1 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "lighting_brightness_level", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Lighting Brightness Level", + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "exemplar": false, + "expr": "lighting_power_usage_kwh", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Lighting Power Usage", + "type": "stat" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 22, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "", + "mode": "markdown" + }, + "pluginVersion": "11.3.0", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 20, + "panels": [], + "title": "Refrigerator", + "type": "row" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0": { + "color": "blue", + "index": 0, + "text": "Closed" + }, + "1": { + "color": "red", + "index": 1, + "text": "Open" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 9 + }, + "id": 1, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "exemplar": false, + "expr": "refrigerator_door_open", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "{{device_id}}", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "Refrigerator Door", + "type": "bargauge" + }, + { + "datasource": { + "name": "${datasource}", + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + }, + { + "color": "#EAB839", + "value": 20 + }, + { + "color": "red", + "value": 30 + } + ] + }, + "unit": "celsius" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 9, + "x": 7, + "y": 9 + }, + "id": 4, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "refrigerator_temperature_celsius", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Refrigerator Temperature", + "type": "gauge" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 9 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "exemplar": false, + "expr": "refrigerator_power_usage_kwh", + "format": "time_series", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Refrigerator Power Usage", + "type": "stat" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 23, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "", + "mode": "markdown" + }, + "pluginVersion": "11.3.0", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 17, + "panels": [], + "title": "HVAC", + "type": "row" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0": { + "color": "blue", + "index": 0, + "text": "Cooling" + }, + "1": { + "color": "orange", + "index": 1, + "text": "Heating" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 6, + "w": 5, + "x": 0, + "y": 17 + }, + "id": 7, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "exemplar": false, + "expr": "hvac_mode", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "{{device_id}}", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "HVAC Mode", + "type": "bargauge" + }, + { + "datasource": { + "name": "${datasource}", + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd", + "seriesBy": "last" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 5, + "x": 5, + "y": 17 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "hvac_power_usage_kwh", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "HVAC Power Usage", + "type": "stat" + }, + { + "datasource": { + "name": "${datasource}", + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 50, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + }, + { + "color": "yellow", + "value": 15 + }, + { + "color": "#6ED0E0", + "value": 30 + } + ] + }, + "unit": "celsius" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 10, + "y": 17 + }, + "id": 9, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "exemplar": false, + "expr": "hvac_temperature_celsius", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "HVAC Temperature", + "type": "gauge" + }, + { + "datasource": { + "name": "${datasource}", + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + }, + { + "color": "orange", + "value": 40 + }, + { + "color": "#6ED0E0", + "value": 60 + } + ] + }, + "unit": "humidity" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 17, + "y": 17 + }, + "id": 15, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "hvac_humidity_percent", + "hide": false, + "instant": true, + "legendFormat": "{{device_id}}", + "range": false, + "refId": "A" + } + ], + "title": "HVAC Humidity", + "type": "gauge" + } + ], + "preload": false, + "refresh": "5s", + "schemaVersion": 40, + "tags": [ + "stores" + ], + "templating": { + "list": [ + { + "current": { + "text": "chicago", + "value": "ae2dreulofdvke" + }, + "includeAll": false, + "label": "Store", + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Store / Industrial Assets Health", + "uid": "ed387aa7-6eac-4c48-8891-4834666ac7ce", + "version": 51, + "weekStart": "" +} \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/monitoring/grafana-app-store-pos.json b/azure_jumpstart_ag/artifacts/monitoring/grafana-app-store-pos.json new file mode 100644 index 0000000000..7ffd87c1d4 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/monitoring/grafana-app-store-pos.json @@ -0,0 +1,1104 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 7, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 41, + "panels": [], + "title": "Point-of-Sale(PoS)", + "type": "row" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 9, + "x": 0, + "y": 1 + }, + "id": 26, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "hidden", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "manual", + "valueMode": "text" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "topk(5,sum(pos_failure_count_total) by (device_id,failure_type))", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{device_id}} - {{failure_type}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "PoS Errors (Top 5)", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "bargauge" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 9, + "y": 1 + }, + "id": 42, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "topk(5,sum(pos_failure_count_total) by (failure_type))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "{{device_id}}", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "PoS Errors (by failure type)", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + }, + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "bargauge" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "POS01" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 7, + "w": 7, + "x": 17, + "y": 1 + }, + "id": 24, + "options": { + "displayMode": "lcd", + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "left", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "increase(pos_items_sold_total[1h])", + "hide": false, + "instant": false, + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A" + } + ], + "title": "POS items Sold (last 1 hour)", + "type": "bargauge" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 22, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "", + "mode": "markdown" + }, + "pluginVersion": "11.3.0", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 40, + "panels": [], + "title": "Self-Checkout", + "type": "row" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "light-red", + "mode": "continuous-YlRd" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 10 + }, + "id": 37, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "increase(auto_checkout_errors_total[1h])", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "{{device_id}}", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "Self-Checkout Errors (last 1 hour)", + "type": "bargauge" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 10, + "x": 8, + "y": 10 + }, + "id": 27, + "options": { + "displayMode": "lcd", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "hidden", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "increase(auto_checkout_items_scanned_total[1h])", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Self-Checkout Items Scanned (last 1 hour)", + "type": "bargauge" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 10 + }, + "id": 28, + "options": { + "displayLabels": [ + "value" + ], + "legend": { + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "increase(auto_checkout_items_scanned_total[1d])", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Self-Checkout Items Scanned (last 1 day)", + "type": "piechart" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 31, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "", + "mode": "markdown" + }, + "pluginVersion": "11.3.0", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 39, + "panels": [], + "title": "Smart Shelf", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "left", + "fillOpacity": 80, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 19 + }, + "id": 34, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xField": "Time", + "xTickLabelRotation": 0, + "xTickLabelSpacing": 200 + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "topk(10,sum(smart_shelf_stock_level) by (device_id, product_id))", + "instant": true, + "legendFormat": "{{device_id}} - {{product_id}}", + "range": false, + "refId": "A" + } + ], + "title": "Smart Shelf Stock Level", + "type": "barchart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "", + "axisPlacement": "right", + "fillOpacity": 80, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 19 + }, + "id": 35, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "vertical", + "showValue": "auto", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 200 + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "topk(10,sum(smart_shelf_threshold) by (device_id, product_id))", + "instant": true, + "legendFormat": "{{device_id}} - {{product_id}}", + "range": false, + "refId": "A" + } + ], + "title": "Smart Shelf Threshold", + "type": "barchart" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 32, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "", + "mode": "markdown" + }, + "pluginVersion": "11.3.0", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 38, + "panels": [], + "title": "Scale", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "masskg" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "scale_tare_weight_kg", + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A" + } + ], + "title": "Scale Tare Weight", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "masskg" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "scale_weight_kg", + "legendFormat": "{{device_id}}", + "range": true, + "refId": "A" + } + ], + "title": "Scale Weight", + "type": "timeseries" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 37 + }, + "id": 23, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "", + "mode": "markdown" + }, + "pluginVersion": "11.3.0", + "title": "", + "transparent": true, + "type": "text" + } + ], + "preload": false, + "refresh": "5s", + "schemaVersion": 40, + "tags": [ + "stores" + ], + "templating": { + "list": [ + { + "current": { + "text": "seattle", + "value": "de2u8l2s3t7uoa" + }, + "includeAll": false, + "label": "Store", + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Store / Point-of-Sale (PoS) Assets Health", + "uid": "49b00f42-7d2d-47bb-b654-3d61ca9f8d6d", + "version": 9, + "weekStart": "" +} \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/monitoring/grafana-app-store-shoppers.json b/azure_jumpstart_ag/artifacts/monitoring/grafana-app-store-shoppers.json new file mode 100644 index 0000000000..7503f68b9e --- /dev/null +++ b/azure_jumpstart_ag/artifacts/monitoring/grafana-app-store-shoppers.json @@ -0,0 +1,2003 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 6, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 46, + "panels": [], + "title": "Aisle Zone", + "type": "row" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 47, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Aisle Zone\n
\n", + "mode": "html" + }, + "pluginVersion": "11.3.0+security-01", + "title": "", + "transparent": true, + "type": "text" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic-by-name" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "total_shoppers" + }, + "properties": [ + { + "id": "displayName", + "value": "Total Shoppers in the zone" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 0, + "y": 3 + }, + "id": 57, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "total_shoppers{camera=\"Aisle Camera\"}", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "", + "type": "stat" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "shoppers_age_10_Aisle_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 10" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_20_Aisle_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 20" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_30_Aisle_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 30" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_40_Aisle_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 40" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_50_Aisle_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 50" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 4, + "y": 3 + }, + "id": 42, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "shoppers_age_10_Aisle_Camera", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "shoppers_age_20_Aisle_Camera", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "shoppers_age_30_Aisle_Camera", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "shoppers_age_40_Aisle_Camera", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "shoppers_age_50_Aisle_Camera", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "E" + } + ], + "title": "", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "stat" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "shoppers_age_20_Aisle_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 20" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_30_Aisle_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 30" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_40_Aisle_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 40" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_50_Aisle_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 50" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_10_Aisle_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 10" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 13, + "x": 11, + "y": 3 + }, + "id": 26, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "shoppers_age_10_Aisle_Camera", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "shoppers_age_20_Aisle_Camera", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "shoppers_age_30_Aisle_Camera", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "shoppers_age_40_Aisle_Camera", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "shoppers_age_50_Aisle_Camera", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "E" + } + ], + "title": "Shoppers (by Age)", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "current_shoppers" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers detected in the zone" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 0, + "y": 11 + }, + "id": 45, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "current_shoppers{camera=~\"Aisle Camera\"}", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "stat" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "detected_total_persons" + }, + "properties": [ + { + "id": "displayName", + "value": "Detected Shoppers" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 4, + "y": 11 + }, + "id": 44, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "detected_total_persons{camera=~\"Aisle Camera\"}", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Shoppers detected", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "detection_fps" + }, + "properties": [ + { + "id": "displayName", + "value": "Detection fps" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 11, + "y": 11 + }, + "id": 50, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "detection_fps{camera=~\"Aisle Camera\"}", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "stat" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "detection_fps" + }, + "properties": [ + { + "id": "displayName", + "value": "Detection fps" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 15, + "y": 11 + }, + "id": 49, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "detection_fps{camera=~\"Aisle Camera\"}", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Detection frame per seconds", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 51, + "panels": [], + "title": "Produce Zone", + "type": "row" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 52, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n Produce Zone\n
\n", + "mode": "html" + }, + "pluginVersion": "11.3.0+security-01", + "title": "", + "transparent": true, + "type": "text" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic-by-name" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "total_shoppers" + }, + "properties": [ + { + "id": "displayName", + "value": "Total shoppers in the zone" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 0, + "y": 22 + }, + "id": 61, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "total_shoppers{camera=\"Produce Camera\"}", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "", + "type": "stat" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#57a1f2", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "shoppers_age_10_Produce_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 10" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_20_Produce_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 20" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_30_Produce_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 30" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_40_Produce_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 40" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_50_Produce_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 50" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 4, + "y": 22 + }, + "id": 62, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "shoppers_age_10_Produce_Camera", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "shoppers_age_20_Produce_Camera", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "shoppers_age_30_Produce_Camera", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "shoppers_age_40_Produce_Camera", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "shoppers_age_50_Produce_Camera", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "E" + } + ], + "title": "", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "stat" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "shoppers_age_20_Produce_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 20" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_30_Produce_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 30" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_10_Produce_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 10" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_40_Produce_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 40" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "shoppers_age_50_Produce_Camera" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers Age 50" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 13, + "x": 11, + "y": 22 + }, + "id": 63, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "shoppers_age_10_Produce_Camera", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "shoppers_age_20_Produce_Camera", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "shoppers_age_30_Produce_Camera", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "shoppers_age_40_Produce_Camera", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "shoppers_age_50_Produce_Camera", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "E" + } + ], + "title": "Shoppers (by Age)", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "current_shoppers" + }, + "properties": [ + { + "id": "displayName", + "value": "Shoppers detected in the zone" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 0, + "y": 30 + }, + "id": 64, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "current_shoppers{camera=~\"Produce Camera\"}", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "stat" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "detected_total_persons" + }, + "properties": [ + { + "id": "displayName", + "value": "Detected Shoppers" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 4, + "y": 30 + }, + "id": 65, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "detected_total_persons{camera=~\"Produce Camera\"}", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Shoppers detected", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "detection_fps" + }, + "properties": [ + { + "id": "displayName", + "value": "Detection fps" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 11, + "y": 30 + }, + "id": 66, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "detection_fps{camera=~\"Produce Camera\"}", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "stat" + }, + { + "datasource": { + "default": false, + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "detection_fps" + }, + "properties": [ + { + "id": "displayName", + "value": "Detection fps" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 15, + "y": 30 + }, + "id": 67, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.0+security-01", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "detection_fps{camera=~\"Produce Camera\"}", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Detection frame per seconds", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)_(.*)", + "renamePattern": "$1 $2" + } + } + ], + "type": "timeseries" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 38 + }, + "id": 60, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "", + "mode": "markdown" + }, + "pluginVersion": "11.3.0+security-01", + "title": "", + "transparent": true, + "type": "text" + } + ], + "preload": false, + "refresh": "5s", + "schemaVersion": 40, + "tags": [ + "stores" + ], + "templating": { + "list": [ + { + "current": { + "text": "chicago", + "value": "de3ubqvmlxaf4d" + }, + "includeAll": false, + "label": "Store", + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Store / Shopper Insights", + "uid": "23e1bc2e-e700-4a2b-b562-34e9eaef68b8", + "version": 5, + "weekStart": "" +} \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/monitoring/grafana-app-workloads.json b/azure_jumpstart_ag/artifacts/monitoring/grafana-app-workloads.json new file mode 100644 index 0000000000..6f1b6d7a0d --- /dev/null +++ b/azure_jumpstart_ag/artifacts/monitoring/grafana-app-workloads.json @@ -0,0 +1,2203 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 10, + "links": [], + "panels": [ + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 14, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "CPU Usage", + "type": "row" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 15, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "CPU Quota", + "type": "row" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #A" + }, + "properties": [ + { + "id": "displayName", + "value": "CPU Usage" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #B" + }, + "properties": [ + { + "id": "displayName", + "value": "CPU Requests" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #C" + }, + "properties": [ + { + "id": "displayName", + "value": "CPU Requests %" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #D" + }, + "properties": [ + { + "id": "displayName", + "value": "CPU Limits" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #E" + }, + "properties": [ + { + "id": "displayName", + "value": "CPU Limits %" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "pod" + }, + "properties": [ + { + "id": "displayName", + "value": "Pod" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Drill down", + "url": "/d/9701f5d6-af2d-442b-a2a4-d4d05f9b79b1/k8s-resources-pod?var-datasource=$datasource&var-namespace=$namespace&from=$__from&to=$__to&var-pod=$__value" + } + ] + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 2, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "11.2.2+security-01", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "A" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "B" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n/sum(\r\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "C" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "D" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n/sum(\r\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", namespace=\"$namespace\", resource=\"cpu\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "E" + } + ], + "title": "CPU Quota", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 16, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Memory Usage", + "type": "row" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n container_memory_working_set_bytes{namespace=\"$namespace\", container!=\"\", image!=\"\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "title": "Memory Usage", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 17, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Memory Quota", + "type": "row" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "custom": { + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #A" + }, + "properties": [ + { + "id": "displayName", + "value": "Memory Usage" + }, + { + "id": "unit", + "value": "bytes" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #B" + }, + "properties": [ + { + "id": "displayName", + "value": "Memory Requests" + }, + { + "id": "unit", + "value": "bytes" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #C" + }, + "properties": [ + { + "id": "displayName", + "value": "Memory Requests %" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #D" + }, + "properties": [ + { + "id": "displayName", + "value": "Memory Limits" + }, + { + "id": "unit", + "value": "bytes" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #E" + }, + "properties": [ + { + "id": "displayName", + "value": "Memory Limits %" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "pod" + }, + "properties": [ + { + "id": "displayName", + "value": "Pod" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Drill down", + "url": "/d/9701f5d6-af2d-442b-a2a4-d4d05f9b79b1/k8s-resources-pod?var-datasource=$datasource&var-namespace=$namespace&from=$__from&to=$__to&var-pod=$__value" + } + ] + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 4, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "11.2.2", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n container_memory_working_set_bytes{namespace=\"$namespace\", container!=\"\", image!=\"\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "A" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", namespace=\"$namespace\", resource=\"memory\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "B" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n container_memory_working_set_bytes{namespace=\"$namespace\", container!=\"\", image!=\"\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n/sum(\r\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", namespace=\"$namespace\", resource=\"memory\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "C" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", namespace=\"$namespace\", resource=\"memory\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "D" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(\r\n container_memory_working_set_bytes{namespace=\"$namespace\", container!=\"\", image!=\"\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n/sum(\r\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", namespace=\"$namespace\", resource=\"memory\"}\r\n * on(namespace,pod)\r\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\r\n) by (pod)\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "E" + } + ], + "title": "Memory Quota", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 18, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Current Network Usage", + "type": "row" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "custom": { + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #A" + }, + "properties": [ + { + "id": "displayName", + "value": "Current Receive Bandwidth" + }, + { + "id": "unit", + "value": "Bps" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #B" + }, + "properties": [ + { + "id": "displayName", + "value": "Current Transmit Bandwidth" + }, + { + "id": "unit", + "value": "Bps" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #C" + }, + "properties": [ + { + "id": "displayName", + "value": "Rate of Received Packets" + }, + { + "id": "unit", + "value": "pps" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #D" + }, + "properties": [ + { + "id": "displayName", + "value": "Rate of Transmitted Packets" + }, + { + "id": "unit", + "value": "pps" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #E" + }, + "properties": [ + { + "id": "displayName", + "value": "Rate of Received Packets Dropped" + }, + { + "id": "unit", + "value": "pps" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value #F" + }, + "properties": [ + { + "id": "displayName", + "value": "Rate of Transmitted Packets Dropped" + }, + { + "id": "unit", + "value": "pps" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "pod" + }, + "properties": [ + { + "id": "displayName", + "value": "Pod" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Drill down", + "url": "/d/9701f5d6-af2d-442b-a2a4-d4d05f9b79b1/k8s-resources-pod?var-datasource=$datasource&var-namespace=$namespace&from=$__from&to=$__to&var-pod=$__value" + } + ] + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 33 + }, + "id": 5, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "11.2.2", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_receive_bytes_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "A" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "B" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_receive_packets_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "C" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_transmit_packets_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "D" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "E" + }, + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "table", + "instant": true, + "legendFormat": "", + "refId": "F" + } + ], + "title": "Current Network Usage", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 19, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Bandwidth", + "type": "row" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 41 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_receive_bytes_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "title": "Receive Bandwidth", + "type": "timeseries" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 41 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "title": "Transmit Bandwidth", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 20, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Average Container Bandwidth by Pod", + "type": "row" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 49 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(avg(irate(container_network_receive_bytes_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "title": "Average Container Bandwidth by Pod: Received", + "type": "timeseries" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 49 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(avg(irate(container_network_transmit_bytes_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "title": "Average Container Bandwidth by Pod: Transmitted", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 56 + }, + "id": 21, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Rate of Packets", + "type": "row" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 57 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_receive_packets_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "title": "Rate of Received Packets", + "type": "timeseries" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 57 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_transmit_packets_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "title": "Rate of Transmitted Packets", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 64 + }, + "id": 22, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Rate of Packets Dropped", + "type": "row" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 65 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "title": "Rate of Received Packets Dropped", + "type": "timeseries" + }, + { + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 65 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.4.7", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "(sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", namespace=\"$namespace\"}[$__rate_interval])\r\n* on (namespace,pod)\r\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\r\n", + "format": "time_series", + "legendFormat": "{{pod}}", + "refId": "A" + } + ], + "title": "Rate of Transmitted Packets Dropped", + "type": "timeseries" + } + ], + "refresh": "1m", + "schemaVersion": 39, + "tags": [ + "workloads" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "chicago", + "value": "ae1dnyprv0zr4a" + }, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": { + "selected": false, + "text": "azure-arc", + "value": "azure-arc" + }, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(kube_namespace_status_phase{job=\"kube-state-metrics\", namespace=~\".*contoso.*\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "deployment", + "value": "deployment" + }, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "type", + "options": [], + "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\"}, workload_type)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "cluster-metadata-operator", + "value": "cluster-metadata-operator" + }, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "workload", + "options": [], + "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{namespace=\"$namespace\", workload_type=\"$type\"}, workload)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Kubernetes / Workload", + "uid": "3151475894614845ba54456099696738ff", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/monitoring/grafana-cluster-global.json b/azure_jumpstart_ag/artifacts/monitoring/grafana-cluster-global.json index 66e4013aa1..2369c958b1 100644 --- a/azure_jumpstart_ag/artifacts/monitoring/grafana-cluster-global.json +++ b/azure_jumpstart_ag/artifacts/monitoring/grafana-cluster-global.json @@ -2638,8 +2638,7 @@ "schemaVersion": 37, "style": "dark", "tags": [ - "Kubernetes", - "Prometheus" + "Kubernetes" ], "templating": { "list": [ @@ -2715,7 +2714,7 @@ "to": "now" }, "timepicker": {}, - "timezone": "", + "timezone": "browser", "title": "Kubernetes / Views / Global", "uid": "k8s_views_global", "version": 28, diff --git a/azure_jumpstart_ag/artifacts/monitoring/grafana-node-exporter-full-v2.json b/azure_jumpstart_ag/artifacts/monitoring/grafana-node-exporter-full-v2.json new file mode 100644 index 0000000000..4826f910ac --- /dev/null +++ b/azure_jumpstart_ag/artifacts/monitoring/grafana-node-exporter-full-v2.json @@ -0,0 +1,23418 @@ +{ + "__inputs": [ + { + "name": "datasource", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.5.2" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "$$hashKey": "object:1058", + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 1860, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "external link", + "tags": [], + "targetBlank": true, + "title": "GitHub", + "type": "link", + "url": "https://github.com/rfmoz/grafana-dashboards" + }, + { + "icon": "external link", + "tags": [], + "targetBlank": true, + "title": "Grafana", + "type": "link", + "url": "https://grafana.com/grafana/dashboards/1860" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 261, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Quick CPU / Mem / Disk", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Busy state of all CPU cores together", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 85 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 1 + }, + "id": 20, + "links": [], + "options": { + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "(sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode!=\"idle\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))) * 100", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "range": true, + "refId": "A", + "step": 240 + } + ], + "title": "CPU Busy", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Busy state of all CPU cores together (5 min average)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 85 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 3, + "y": 1 + }, + "id": 155, + "links": [], + "options": { + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "avg(node_load5{instance=\"$node\",job=\"$job\"}) / count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)) * 100", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "A", + "step": 240 + } + ], + "title": "Sys Load (5m avg)", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Busy state of all CPU cores together (15 min average)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 85 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 6, + "y": 1 + }, + "id": 19, + "links": [], + "options": { + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "avg(node_load15{instance=\"$node\",job=\"$job\"}) / count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)) * 100", + "hide": false, + "intervalFactor": 1, + "refId": "A", + "step": 240 + } + ], + "title": "Sys Load (15m avg)", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Non available RAM memory", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 80 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 9, + "y": 1 + }, + "hideTimeOverride": false, + "id": 16, + "links": [], + "options": { + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "((node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"}) / (node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"} )) * 100", + "format": "time_series", + "hide": true, + "intervalFactor": 1, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "100 - ((node_memory_MemAvailable_bytes{instance=\"$node\",job=\"$job\"} * 100) / node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "B", + "step": 240 + } + ], + "title": "RAM Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Used Swap", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 10 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 25 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 12, + "y": 1 + }, + "id": 21, + "links": [], + "options": { + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "((node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapFree_bytes{instance=\"$node\",job=\"$job\"}) / (node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"} )) * 100", + "intervalFactor": 1, + "refId": "A", + "step": 240 + } + ], + "title": "SWAP Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Used Root FS", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 80 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 15, + "y": 1 + }, + "id": 154, + "links": [], + "options": { + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "100 - ((node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",mountpoint=\"/\",fstype!=\"rootfs\"} * 100) / node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",mountpoint=\"/\",fstype!=\"rootfs\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 240 + } + ], + "title": "Root FS Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Total number of CPU cores", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 18, + "y": 1 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu))", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A", + "step": 240 + } + ], + "title": "CPU Cores", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "System uptime", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 20, + "y": 1 + }, + "hideTimeOverride": true, + "id": 15, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_time_seconds{instance=\"$node\",job=\"$job\"} - node_boot_time_seconds{instance=\"$node\",job=\"$job\"}", + "intervalFactor": 1, + "refId": "A", + "step": 240 + } + ], + "title": "Uptime", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Total RootFS", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 70 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 18, + "y": 3 + }, + "id": 23, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",mountpoint=\"/\",fstype!=\"rootfs\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "A", + "step": 240 + } + ], + "title": "RootFS Total", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Total RAM", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 20, + "y": 3 + }, + "id": 75, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"}", + "intervalFactor": 1, + "refId": "A", + "step": 240 + } + ], + "title": "RAM Total", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Total SWAP", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 22, + "y": 3 + }, + "id": 18, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.5.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"}", + "intervalFactor": 1, + "refId": "A", + "step": 240 + } + ], + "title": "SWAP Total", + "type": "stat" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 263, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Basic CPU / Mem / Net / Disk", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Basic CPU info", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Busy Iowait" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Idle" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy Iowait" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Idle" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy System" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy User" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy Other" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 77, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "width": 250 + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"system\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Busy System", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"user\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Busy User", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"iowait\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Busy Iowait", + "range": true, + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=~\".*irq\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Busy IRQs", + "range": true, + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode!='idle',mode!='user',mode!='system',mode!='iowait',mode!='irq',mode!='softirq'}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Busy Other", + "range": true, + "refId": "E", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"idle\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Idle", + "range": true, + "refId": "F", + "step": 240 + } + ], + "title": "CPU Basic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Basic memory usage", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "SWAP Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM Cache + Buffer" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Available" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#DEDAF7", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 6 + }, + "id": 78, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "RAM Total", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"} - (node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"} + node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"} + node_memory_SReclaimable_bytes{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "RAM Used", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"} + node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"} + node_memory_SReclaimable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "RAM Cache + Buffer", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "RAM Free", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "(node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapFree_bytes{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SWAP Used", + "refId": "E", + "step": 240 + } + ], + "title": "Memory Basic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Basic network info per interface", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Recv_bytes_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_drop_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_errs_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CCA300", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_bytes_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_drop_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_errs_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CCA300", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_drop_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#967302", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_errs_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_bytes_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_drop_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#967302", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_errs_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 74, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_receive_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "recv {{device}}", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_transmit_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "trans {{device}} ", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Basic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Disk space used of all filesystems mounted", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 152, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "100 - ((node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'} * 100) / node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}}", + "refId": "A", + "step": 240 + } + ], + "title": "Disk Space Used Basic", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 265, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "CPU / Memory / Net / Disk", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "percentage", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 70, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Idle - Waiting for something to happen" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Iowait - Waiting for I/O to complete" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Irq - Servicing interrupts" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Nice - Niced processes executing in user mode" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Softirq - Servicing softirqs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Steal - Time spent in other operating systems when running in a virtualized environment" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCE2DE", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "System - Processes executing in kernel mode" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "User - Normal processes executing in user mode" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#5195CE", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 3, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 250 + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"system\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "System - Processes executing in kernel mode", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"user\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "User - Normal processes executing in user mode", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"nice\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Nice - Niced processes executing in user mode", + "range": true, + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"iowait\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Iowait - Waiting for I/O to complete", + "range": true, + "refId": "E", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"irq\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Irq - Servicing interrupts", + "range": true, + "refId": "F", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"softirq\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Softirq - Servicing softirqs", + "range": true, + "refId": "G", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"steal\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Steal - Time spent in other operating systems when running in a virtualized environment", + "range": true, + "refId": "H", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"idle\"}[$__rate_interval])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Idle - Waiting for something to happen", + "range": true, + "refId": "J", + "step": 240 + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap - Swap memory usage" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused - Free memory unassigned" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Hardware Corrupted - *./" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 24, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"} - node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"} - node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"} - node_memory_Slab_bytes{instance=\"$node\",job=\"$job\"} - node_memory_PageTables_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapCached_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Apps - Memory used by user-space applications", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_PageTables_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "PageTables - Memory used to map between virtual and physical memory addresses", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_SwapCached_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SwapCache - Memory that keeps track of pages that have been fetched from swap but not yet been modified", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Slab_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Slab - Memory used by the kernel to cache data structures for its own use (caches like inode, dentry, etc)", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Cache - Parked file data (file content) cache", + "refId": "E", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Buffers - Block device (e.g. harddisk) cache", + "refId": "F", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Unused - Free memory unassigned", + "refId": "G", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "(node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapFree_bytes{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Swap - Swap space used", + "refId": "H", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_HardwareCorrupted_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working", + "refId": "I", + "step": 240 + } + ], + "title": "Memory Stack", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bits out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "receive_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "receive_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 33 + }, + "id": 84, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_receive_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_transmit_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 33 + }, + "id": 156, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'} - node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}}", + "refId": "A", + "step": 240 + } + ], + "title": "Disk Space Used", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "IO read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 229, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_reads_completed_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "intervalFactor": 4, + "legendFormat": "{{device}} - Reads completed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_writes_completed_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Writes completed", + "refId": "B", + "step": 240 + } + ], + "title": "Disk IOps", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "io time" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*read*./" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 45 + }, + "id": 42, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_read_bytes_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{device}} - Successfully read bytes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_written_bytes_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{device}} - Successfully written bytes", + "refId": "B", + "step": 240 + } + ], + "title": "I/O Usage Read / Write", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "%util", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "io time" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 57 + }, + "id": 127, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_io_time_seconds_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"} [$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}}", + "refId": "A", + "step": 240 + } + ], + "title": "I/O Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "percentage", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 70, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 3, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^Guest - /" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#5195ce", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^GuestNice - /" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#c15c17", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 57 + }, + "id": 319, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_guest_seconds_total{instance=\"$node\",job=\"$job\", mode=\"user\"}[1m])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[1m])))", + "hide": false, + "legendFormat": "Guest - Time spent running a virtual CPU for a guest operating system", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_guest_seconds_total{instance=\"$node\",job=\"$job\", mode=\"nice\"}[1m])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[1m])))", + "hide": false, + "legendFormat": "GuestNice - Time spent running a niced guest (virtual CPU for guest operating system)", + "range": true, + "refId": "B" + } + ], + "title": "CPU spent seconds in guests (VMs)", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 69 + }, + "id": 266, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Memory Meminfo", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 70 + }, + "id": 136, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Inactive_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Inactive - Memory which has been less recently used. It is more eligible to be reclaimed for other purposes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Active_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Active - Memory that has been used more recently and usually not reclaimed unless absolutely necessary", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Active / Inactive", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*CommitLimit - *./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 70 + }, + "id": 135, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Committed_AS_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Committed_AS - Amount of memory presently allocated on the system", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_CommitLimit_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CommitLimit - Amount of memory currently available to be allocated on the system", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Committed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 80 + }, + "id": 191, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Inactive_file_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inactive_file - File-backed memory on inactive LRU list", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Inactive_anon_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inactive_anon - Anonymous and swap cache on inactive LRU list, including tmpfs (shmem)", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Active_file_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Active_file - File-backed memory on active LRU list", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Active_anon_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Active_anon - Anonymous and swap cache on active least-recently-used (LRU) list, including tmpfs", + "refId": "D", + "step": 240 + } + ], + "title": "Memory Active / Inactive Detail", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 80 + }, + "id": 130, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Writeback_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Writeback - Memory which is actively being written back to disk", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_WritebackTmp_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "WritebackTmp - Memory used by FUSE for temporary writeback buffers", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Dirty_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Dirty - Memory which is waiting to get written back to the disk", + "refId": "C", + "step": 240 + } + ], + "title": "Memory Writeback and Dirty", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ShmemHugePages - Memory used by shared memory (shmem) and tmpfs allocated with huge pages" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ShmemHugePages - Memory used by shared memory (shmem) and tmpfs allocated with huge pages" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 90 + }, + "id": 138, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Mapped_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Mapped - Used memory in mapped pages files which have been mapped, such as libraries", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Shmem_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Shmem - Used shared memory (shared between several processes, thus including RAM disks)", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_ShmemHugePages_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "ShmemHugePages - Memory used by shared memory (shmem) and tmpfs allocated with huge pages", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_ShmemPmdMapped_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "ShmemPmdMapped - Amount of shared (shmem/tmpfs) memory backed by huge pages", + "refId": "D", + "step": 240 + } + ], + "title": "Memory Shared and Mapped", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 90 + }, + "id": 131, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_SUnreclaim_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SUnreclaim - Part of Slab, that cannot be reclaimed on memory pressure", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_SReclaimable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SReclaimable - Part of Slab, that might be reclaimed, such as caches", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Slab", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 100 + }, + "id": 70, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_VmallocChunk_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "VmallocChunk - Largest contiguous block of vmalloc area which is free", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_VmallocTotal_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "VmallocTotal - Total size of vmalloc memory area", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_VmallocUsed_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "VmallocUsed - Amount of vmalloc area which is used", + "refId": "C", + "step": 240 + } + ], + "title": "Memory Vmalloc", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 100 + }, + "id": 159, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Bounce_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Bounce - Memory used for block device bounce buffers", + "refId": "A", + "step": 240 + } + ], + "title": "Memory Bounce", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Inactive *./" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 110 + }, + "id": 129, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_AnonHugePages_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "AnonHugePages - Memory in anonymous huge pages", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_AnonPages_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "AnonPages - Memory in user pages not backed by files", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Anonymous", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 110 + }, + "id": 160, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_KernelStack_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "KernelStack - Kernel memory stack. This is not reclaimable", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Percpu_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "PerCPU - Per CPU memory allocated dynamically by loadable modules", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Kernel / CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "pages", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 120 + }, + "id": 140, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_HugePages_Free{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages_Free - Huge pages in the pool that are not yet allocated", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_HugePages_Rsvd{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages_Rsvd - Huge pages for which a commitment to allocate from the pool has been made, but no allocation has yet been made", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_HugePages_Surp{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages_Surp - Huge pages in the pool above the value in /proc/sys/vm/nr_hugepages", + "refId": "C", + "step": 240 + } + ], + "title": "Memory HugePages Counter", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 120 + }, + "id": 71, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_HugePages_Total{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages - Total size of the pool of huge pages", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Hugepagesize_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Hugepagesize - Huge Page size", + "refId": "B", + "step": 240 + } + ], + "title": "Memory HugePages Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 130 + }, + "id": 128, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_DirectMap1G_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "DirectMap1G - Amount of pages mapped as this size", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_DirectMap2M_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "DirectMap2M - Amount of pages mapped as this size", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_DirectMap4k_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "DirectMap4K - Amount of pages mapped as this size", + "refId": "C", + "step": 240 + } + ], + "title": "Memory DirectMap", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 130 + }, + "id": 137, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Unevictable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unevictable - Amount of unevictable memory that can't be swapped out for a variety of reasons", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_Mlocked_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "MLocked - Size of pages locked to memory using the mlock() system call", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Unevictable and MLocked", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 140 + }, + "id": 132, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_memory_NFS_Unstable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "NFS Unstable - Memory in NFS pages sent to the server, but not yet committed to the storage", + "refId": "A", + "step": 240 + } + ], + "title": "Memory NFS", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 150 + }, + "id": 267, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Memory Vmstat", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "pages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*out/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 151 + }, + "id": 176, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_vmstat_pgpgin{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pagesin - Page in operations", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_vmstat_pgpgout{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pagesout - Page out operations", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Pages In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "pages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*out/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 151 + }, + "id": 22, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_vmstat_pswpin{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pswpin - Pages swapped in", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_vmstat_pswpout{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pswpout - Pages swapped out", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Pages Swap In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "faults", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Pgfault - Page major and minor fault operations" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 161 + }, + "id": 175, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_vmstat_pgfault{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pgfault - Page major and minor fault operations", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_vmstat_pgmajfault{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pgmajfault - Major page fault operations", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_vmstat_pgfault{instance=\"$node\",job=\"$job\"}[$__rate_interval]) - irate(node_vmstat_pgmajfault{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pgminfault - Minor page fault operations", + "refId": "C", + "step": 240 + } + ], + "title": "Memory Page Faults", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 161 + }, + "id": 307, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_vmstat_oom_kill{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "oom killer invocations ", + "refId": "A", + "step": 240 + } + ], + "title": "OOM Killer", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 171 + }, + "id": 293, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "System Timesync", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Variation*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 172 + }, + "id": 260, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_timex_estimated_error_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Estimated error in seconds", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_timex_offset_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Time offset in between local system and reference clock", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_timex_maxerror_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum error in seconds", + "refId": "C", + "step": 240 + } + ], + "title": "Time Synchronized Drift", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 172 + }, + "id": 291, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_timex_loop_time_constant{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Phase-locked loop time adjust", + "refId": "A", + "step": 240 + } + ], + "title": "Time PLL Adjust", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Variation*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 182 + }, + "id": 168, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_timex_sync_status{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Is clock synchronized to a reliable server (1 = yes, 0 = no)", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_timex_frequency_adjustment_ratio{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Local clock frequency adjustment", + "refId": "B", + "step": 240 + } + ], + "title": "Time Synchronized Status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 182 + }, + "id": 294, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_timex_tick_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Seconds between clock ticks", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_timex_tai_offset_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "International Atomic Time (TAI) offset", + "refId": "B", + "step": 240 + } + ], + "title": "Time Misc", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 192 + }, + "id": 312, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "System Processes", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 193 + }, + "id": 62, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_procs_blocked{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processes blocked waiting for I/O to complete", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_procs_running{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processes in runnable state", + "refId": "B", + "step": 240 + } + ], + "title": "Processes Status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 193 + }, + "id": 315, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_processes_state{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ state }}", + "refId": "A", + "step": 240 + } + ], + "title": "Processes State", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "forks / sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 203 + }, + "id": 148, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_forks_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Processes forks second", + "refId": "A", + "step": 240 + } + ], + "title": "Processes Forks", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max.*/" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 203 + }, + "id": 149, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(process_virtual_memory_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Processes virtual memory size in bytes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "process_resident_memory_max_bytes{instance=\"$node\",job=\"$job\"}", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum amount of virtual memory available in bytes", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(process_virtual_memory_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Processes virtual memory size in bytes", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(process_virtual_memory_max_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum amount of virtual memory available in bytes", + "refId": "D", + "step": 240 + } + ], + "title": "Processes Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PIDs limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 213 + }, + "id": 313, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_processes_pids{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Number of PIDs", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_processes_max_processes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "PIDs limit", + "refId": "B", + "step": 240 + } + ], + "title": "PIDs Number and Limit", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*waiting.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 213 + }, + "id": 305, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_schedstat_running_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }} - seconds spent running a process", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_schedstat_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }} - seconds spent by processing waiting for this CPU", + "refId": "B", + "step": 240 + } + ], + "title": "Process schedule stats Running / Waiting", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Threads limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 223 + }, + "id": 314, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_processes_threads{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Allocated threads", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_processes_max_threads{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Threads limit", + "refId": "B", + "step": 240 + } + ], + "title": "Threads Number and Limit", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 233 + }, + "id": 269, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "System Misc", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 234 + }, + "id": 8, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_context_switches_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Context switches", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_intr_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Interrupts", + "refId": "B", + "step": 240 + } + ], + "title": "Context Switches / Interrupts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 234 + }, + "id": 7, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_load1{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Load 1m", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_load5{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Load 5m", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_load15{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Load 15m", + "refId": "C", + "step": 240 + } + ], + "title": "System Load", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Critical*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 244 + }, + "id": 259, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_interrupts_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ type }} - {{ info }}", + "refId": "A", + "step": 240 + } + ], + "title": "Interrupts Detail", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 244 + }, + "id": 306, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_schedstat_timeslices_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }}", + "refId": "A", + "step": 240 + } + ], + "title": "Schedule timeslices executed by each cpu", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 254 + }, + "id": 151, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_entropy_available_bits{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Entropy available to random number generators", + "refId": "A", + "step": 240 + } + ], + "title": "Entropy", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 254 + }, + "id": 308, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(process_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Time spent", + "refId": "A", + "step": 240 + } + ], + "title": "CPU time spent in user and system contexts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 264 + }, + "id": 64, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "process_max_fds{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum open file descriptors", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "process_open_fds{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Open file descriptors", + "refId": "B", + "step": 240 + } + ], + "title": "File Descriptors", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 274 + }, + "id": 304, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Hardware Misc", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "temperature", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "celsius" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Critical*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 275 + }, + "id": 158, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_hwmon_temp_celsius{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip }} {{ sensor }} temp", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_hwmon_temp_crit_alarm_celsius{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip }} {{ sensor }} Critical Alarm", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_hwmon_temp_crit_celsius{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip }} {{ sensor }} Critical", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_hwmon_temp_crit_hyst_celsius{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip }} {{ sensor }} Critical Historical", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_hwmon_temp_max_celsius{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip }} {{ sensor }} Max", + "refId": "E", + "step": 240 + } + ], + "title": "Hardware temperature monitor", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 275 + }, + "id": 300, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_cooling_device_cur_state{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Current {{ name }} in {{ type }}", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_cooling_device_max_state{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Max {{ name }} in {{ type }}", + "refId": "B", + "step": 240 + } + ], + "title": "Throttle cooling device", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 285 + }, + "id": 302, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_power_supply_online{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ power_supply }} online", + "refId": "A", + "step": 240 + } + ], + "title": "Power supply", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 295 + }, + "id": 296, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Systemd", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 296 + }, + "id": 297, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_systemd_socket_accepted_connections_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ name }} Connections", + "refId": "A", + "step": 240 + } + ], + "title": "Systemd Sockets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF9830", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Deactivating" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFCB7D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Activating" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C8F2C2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 296 + }, + "id": 298, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"activating\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Activating", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"active\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Active", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"deactivating\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Deactivating", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"failed\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Failed", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"inactive\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Inactive", + "refId": "E", + "step": 240 + } + ], + "title": "Systemd Units State", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 306 + }, + "id": 270, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Storage Disk", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "The number (after merges) of I/O requests completed per second for the device", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "IO read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 307 + }, + "id": 9, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_reads_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 4, + "legendFormat": "{{device}} - Reads completed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_writes_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Writes completed", + "refId": "B", + "step": 240 + } + ], + "title": "Disk IOps Completed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "The number of bytes read from or written to the device per second", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 307 + }, + "id": 33, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_read_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "{{device}} - Read bytes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_written_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Written bytes", + "refId": "B", + "step": 240 + } + ], + "title": "Disk R/W Data", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "The average time for requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "time. read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 317 + }, + "id": 37, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_read_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval]) / irate(node_disk_reads_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - Read wait time avg", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_write_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval]) / irate(node_disk_writes_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Write wait time avg", + "refId": "B", + "step": 240 + } + ], + "title": "Disk Average Wait Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "The average queue length of the requests that were issued to the device", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "aqu-sz", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 317 + }, + "id": 35, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_io_time_weighted_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}}", + "refId": "A", + "step": 240 + } + ], + "title": "Average Queue Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "The number of read and write requests merged per second that were queued to the device", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "I/Os", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 327 + }, + "id": 133, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_reads_merged_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Read merged", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_writes_merged_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Write merged", + "refId": "B", + "step": 240 + } + ], + "title": "Disk R/W Merged", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Percentage of elapsed time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100% for devices serving requests serially. But for devices serving requests in parallel, such as RAID arrays and modern SSDs, this number does not reflect their performance limits.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "%util", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 327 + }, + "id": 36, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_io_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - IO", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_discard_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - discard", + "refId": "B", + "step": 240 + } + ], + "title": "Time Spent Doing I/Os", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "The number of outstanding requests at the instant the sample was taken. Incremented as requests are given to appropriate struct request_queue and decremented as they finish.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Outstanding req.", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 337 + }, + "id": 34, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_disk_io_now{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - IO now", + "refId": "A", + "step": 240 + } + ], + "title": "Instantaneous Queue Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "IOs", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 337 + }, + "id": 301, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_discards_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - Discards completed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_disk_discards_merged_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Discards merged", + "refId": "B", + "step": 240 + } + ], + "title": "Disk IOps Discards completed / merged", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 347 + }, + "id": 271, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Storage Filesystem", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 348 + }, + "id": 43, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Available", + "metric": "", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filesystem_free_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": true, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Free", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": true, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Size", + "refId": "C", + "step": 240 + } + ], + "title": "Filesystem space available", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "file nodes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 348 + }, + "id": 41, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filesystem_files_free{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Free file nodes", + "refId": "A", + "step": 240 + } + ], + "title": "File Nodes Free", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "files", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 358 + }, + "id": 28, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filefd_maximum{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Max open files", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filefd_allocated{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Open files", + "refId": "B", + "step": 240 + } + ], + "title": "File Descriptor", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "file Nodes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 358 + }, + "id": 219, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filesystem_files{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - File nodes total", + "refId": "A", + "step": 240 + } + ], + "title": "File Nodes Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "/ ReadOnly" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 368 + }, + "id": 44, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filesystem_readonly{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - ReadOnly", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_filesystem_device_error{instance=\"$node\",job=\"$job\",device!~'rootfs',fstype!~'tmpfs'}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Device error", + "refId": "B", + "step": 240 + } + ], + "title": "Filesystem in ReadOnly / Error", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 378 + }, + "id": 272, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Network Traffic", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "receive_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "receive_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 379 + }, + "id": 60, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_receive_packets_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_transmit_packets_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic by Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 379 + }, + "id": 142, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_receive_errs_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive errors", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_transmit_errs_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Rransmit errors", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 389 + }, + "id": 143, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_receive_drop_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive drop", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_transmit_drop_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit drop", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Drop", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 389 + }, + "id": 141, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_receive_compressed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive compressed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_transmit_compressed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit compressed", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Compressed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 399 + }, + "id": 146, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_receive_multicast_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive multicast", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Multicast", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 399 + }, + "id": 144, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_receive_fifo_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive fifo", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_transmit_fifo_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit fifo", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Fifo", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 409 + }, + "id": 145, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_receive_frame_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive frame", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Frame", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 409 + }, + "id": 231, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_transmit_carrier_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Statistic transmit_carrier", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Carrier", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 419 + }, + "id": 232, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_network_transmit_colls_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit colls", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Colls", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "entries", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NF conntrack limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 419 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_nf_conntrack_entries{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "NF conntrack entries", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_nf_conntrack_entries_limit{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "NF conntrack limit", + "refId": "B", + "step": 240 + } + ], + "title": "NF Contrack", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Entries", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 429 + }, + "id": 230, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_arp_entries{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - ARP entries", + "refId": "A", + "step": 240 + } + ], + "title": "ARP Entries", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 429 + }, + "id": 288, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_network_mtu_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - Bytes", + "refId": "A", + "step": 240 + } + ], + "title": "MTU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 439 + }, + "id": 280, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_network_speed_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - Speed", + "refId": "A", + "step": 240 + } + ], + "title": "Speed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 439 + }, + "id": 289, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_network_transmit_queue_length{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - Interface transmit queue length", + "refId": "A", + "step": 240 + } + ], + "title": "Queue Length", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packetes drop (-) / process (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Dropped.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 449 + }, + "id": 290, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_softnet_processed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{cpu}} - Processed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_softnet_dropped_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{cpu}} - Dropped", + "refId": "B", + "step": 240 + } + ], + "title": "Softnet Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 449 + }, + "id": 310, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_softnet_times_squeezed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{cpu}} - Squeezed", + "refId": "A", + "step": 240 + } + ], + "title": "Softnet Out of Quota", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 459 + }, + "id": 309, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_network_up{operstate=\"up\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{interface}} - Operational state UP", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_network_carrier{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "instant": false, + "legendFormat": "{{device}} - Physical link state", + "refId": "B" + } + ], + "title": "Network Operational Status", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 469 + }, + "id": 273, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Network Sockstat", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 470 + }, + "id": 63, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_TCP_alloc{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_alloc - Allocated sockets", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_TCP_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_inuse - Tcp sockets currently in use", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_TCP_mem{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_mem - Used memory for tcp", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_TCP_orphan{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_orphan - Orphan sockets", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_TCP_tw{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_tw - Sockets waiting close", + "refId": "E", + "step": 240 + } + ], + "title": "Sockstat TCP", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 470 + }, + "id": 124, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_UDPLITE_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "UDPLITE_inuse - Udplite sockets currently in use", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_UDP_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "UDP_inuse - Udp sockets currently in use", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_UDP_mem{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "UDP_mem - Used memory for udp", + "refId": "C", + "step": 240 + } + ], + "title": "Sockstat UDP", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 480 + }, + "id": 125, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_FRAG_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "FRAG_inuse - Frag sockets currently in use", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_RAW_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "RAW_inuse - Raw sockets currently in use", + "refId": "C", + "step": 240 + } + ], + "title": "Sockstat FRAG / RAW", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 480 + }, + "id": 220, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_TCP_mem_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "mem_bytes - TCP sockets in that state", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_UDP_mem_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "mem_bytes - UDP sockets in that state", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_FRAG_memory{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 1, + "legendFormat": "FRAG_memory - Used memory for frag", + "refId": "C" + } + ], + "title": "Sockstat Memory Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "sockets", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 490 + }, + "id": 126, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_sockstat_sockets_used{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Sockets_used - Sockets currently in use", + "refId": "A", + "step": 240 + } + ], + "title": "Sockstat Used", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 500 + }, + "id": 274, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Network Netstat", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "octets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 501 + }, + "id": 221, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_IpExt_InOctets{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InOctets - Received octets", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_IpExt_OutOctets{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "OutOctets - Sent octets", + "refId": "B", + "step": 240 + } + ], + "title": "Netstat IP In / Out Octets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 501 + }, + "id": 81, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Ip_Forwarding{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Forwarding - IP forwarding", + "refId": "A", + "step": 240 + } + ], + "title": "Netstat IP Forwarding", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "messages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 511 + }, + "id": 115, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Icmp_InMsgs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InMsgs - Messages which the entity received. Note that this counter includes all those counted by icmpInErrors", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Icmp_OutMsgs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "OutMsgs - Messages which this entity attempted to send. Note that this counter includes all those counted by icmpOutErrors", + "refId": "B", + "step": 240 + } + ], + "title": "ICMP In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "messages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 511 + }, + "id": 50, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Icmp_InErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InErrors - Messages which the entity received but determined as having ICMP-specific errors (bad ICMP checksums, bad length, etc.)", + "refId": "A", + "step": 240 + } + ], + "title": "ICMP Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Snd.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 521 + }, + "id": 55, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Udp_InDatagrams{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InDatagrams - Datagrams received", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Udp_OutDatagrams{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "OutDatagrams - Datagrams sent", + "refId": "B", + "step": 240 + } + ], + "title": "UDP In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 521 + }, + "id": 109, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Udp_InErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InErrors - UDP Datagrams that could not be delivered to an application", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Udp_NoPorts{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "NoPorts - UDP Datagrams received on a port with no listener", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_UdpLite_InErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "InErrors Lite - UDPLite Datagrams that could not be delivered to an application", + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Udp_RcvbufErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "RcvbufErrors - UDP buffer errors received", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Udp_SndbufErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "SndbufErrors - UDP buffer errors send", + "refId": "E", + "step": 240 + } + ], + "title": "UDP Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Snd.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 531 + }, + "id": 299, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Tcp_InSegs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "InSegs - Segments received, including those received in error. This count includes segments received on currently established connections", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Tcp_OutSegs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "OutSegs - Segments sent, including those on current connections but excluding those containing only retransmitted octets", + "refId": "B", + "step": 240 + } + ], + "title": "TCP In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 531 + }, + "id": 104, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_TcpExt_ListenOverflows{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "ListenOverflows - Times the listen queue of a socket overflowed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_TcpExt_ListenDrops{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "ListenDrops - SYNs to LISTEN sockets ignored", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_TcpExt_TCPSynRetrans{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCPSynRetrans - SYN-SYN/ACK retransmits to break down retransmissions in SYN, fast/timeout retransmits", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Tcp_RetransSegs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "RetransSegs - Segments retransmitted - that is, the number of TCP segments transmitted containing one or more previously transmitted octets", + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Tcp_InErrs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "InErrs - Segments received in error (e.g., bad TCP checksums)", + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Tcp_OutRsts{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "OutRsts - Segments sent with RST flag", + "refId": "F" + } + ], + "title": "TCP Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "connections", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*MaxConn *./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 541 + }, + "id": 85, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_netstat_Tcp_CurrEstab{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "CurrEstab - TCP connections for which the current state is either ESTABLISHED or CLOSE- WAIT", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_netstat_Tcp_MaxConn{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "MaxConn - Limit on the total number of TCP connections the entity can support (Dynamic is \"-1\")", + "refId": "B", + "step": 240 + } + ], + "title": "TCP Connections", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Sent.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 541 + }, + "id": 91, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_TcpExt_SyncookiesFailed{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "SyncookiesFailed - Invalid SYN cookies received", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_TcpExt_SyncookiesRecv{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "SyncookiesRecv - SYN cookies received", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_TcpExt_SyncookiesSent{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "SyncookiesSent - SYN cookies sent", + "refId": "C", + "step": 240 + } + ], + "title": "TCP SynCookie", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "connections", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 551 + }, + "id": 82, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Tcp_ActiveOpens{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "ActiveOpens - TCP connections that have made a direct transition to the SYN-SENT state from the CLOSED state", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "irate(node_netstat_Tcp_PassiveOpens{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "PassiveOpens - TCP connections that have made a direct transition to the SYN-RCVD state from the LISTEN state", + "refId": "B", + "step": 240 + } + ], + "title": "TCP Direct Transition", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "Enable with --collector.tcpstat argument on node-exporter", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "connections", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 551 + }, + "id": 320, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"established\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "established - TCP sockets in established state", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"fin_wait2\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "fin_wait2 - TCP sockets in fin_wait2 state", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"listen\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "listen - TCP sockets in listen state", + "range": true, + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"time_wait\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "time_wait - TCP sockets in time_wait state", + "range": true, + "refId": "D", + "step": 240 + } + ], + "title": "TCP Stat", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 561 + }, + "id": 279, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], + "title": "Node Exporter", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 562 + }, + "id": 40, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_scrape_collector_duration_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{collector}} - Scrape duration", + "refId": "A", + "step": 240 + } + ], + "title": "Node Exporter Scrape Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*error.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + }, + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 562 + }, + "id": 157, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_scrape_collector_success{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{collector}} - Scrape success", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "expr": "node_textfile_scrape_error{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{collector}} - Scrape textfile error (1 = true)", + "refId": "B", + "step": 240 + } + ], + "title": "Node Exporter Scrape", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "Kubernetes" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "hide": 0, + "includeAll": false, + "label": "datasource", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Job", + "multi": false, + "name": "job", + "options": [], + "query": { + "query": "label_values(node_uname_info, job)", + "refId": "Prometheus-job-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "definition": "label_values(node_uname_info{job=\"$job\"}, instance)", + "hide": 0, + "includeAll": false, + "label": "Host:", + "multi": false, + "name": "node", + "options": [], + "query": { + "query": "label_values(node_uname_info{job=\"$job\"}, instance)", + "refId": "Prometheus-node-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+", + "value": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+" + }, + "hide": 2, + "includeAll": false, + "multi": false, + "name": "diskdevices", + "options": [ + { + "selected": true, + "text": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+", + "value": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+" + } + ], + "query": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Kubernetes / Cluster / Node Exporter", + "uid": "rYdddlPWk", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/settings/Bookmarks-contoso-hypermarket b/azure_jumpstart_ag/artifacts/settings/Bookmarks-contoso-hypermarket new file mode 100644 index 0000000000..6aa6ab66f9 --- /dev/null +++ b/azure_jumpstart_ag/artifacts/settings/Bookmarks-contoso-hypermarket @@ -0,0 +1,229 @@ +{ + "checksum": "d77f9db622cff666aa1ae0f899c3b4ec", + "roots": { + "bookmark_bar": { + "children": [ { + "children": [ { + "children": [ { + "id": "4", + "name": "backend-api - Chicago", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "backend-api-Chicago-URL" + }, { + "id": "5", + "name": "backend-api - Seattle", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "backend-api-Seattle-URL" + } ], + "id": "3", + "name": "Backend API", + "source": "unknown", + "type": "folder" + }, { + "children": [ { + "id": "7", + "name": "cerebral-api - Chicago", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "cerebral-api-Chicago-URL" + }, { + "id": "8", + "name": "cerebral-api - Seattle", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "cerebral-api-Seattle-URL" + } ], + "id": "6", + "name": "Cerebral-API", + "source": "unknown", + "type": "folder" + }, { + "children": [ { + "id": "10", + "name": "cerebral simulator - Chicago", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "cerebral-simulator-Chicago-URL" + }, { + "id": "11", + "name": "cerebral simulator - Seattle", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "cerebral-simulator-Seattle-URL" + } ], + "id": "9", + "name": "Cerebral-Simulator", + "source": "unknown", + "type": "folder" + }, { + "children": [ { + "id": "13", + "name": "Footfall API - Chicago", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "Footfall-AI-API-Chicago-URL" + }, { + "id": "14", + "name": "Footfall API - Seattle", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "Footfall-AI-API-Seattle-URL" + } ], + "id": "12", + "name": "Footfall-API", + "source": "unknown", + "type": "folder" + } , + { + "children": [ { + "id": "13", + "name": "Main UI - Chicago", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "Main-UI-Chicago-URL" + }, { + "id": "14", + "name": "Main UI - Seattle", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "Main-UI-Seattle-URL" + } ], + "id": "12", + "name": "Main UI", + "source": "unknown", + "type": "folder" + }, + { + "children": [ { + "id": "13", + "name": "Shopper Insights API - Chicago", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "Shopper-Insights-API-Chicago-URL" + }, { + "id": "14", + "name": "Shopper Insights API - Seattle", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "Shopper-Insights-API-Seattle-URL" + } ], + "id": "12", + "name": "Shopper Insights API", + "source": "unknown", + "type": "folder" + }], + "id": "2", + "name": "Control Center", + "source": "unknown", + "type": "folder" + }, { + "children": [ { + "id": "16", + "name": "Grafana", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "Grafana-URL" + }], + "id": "15", + "name": "Grafana", + "source": "unknown", + "type": "folder" + }, { + "children": [ { + "id": "16", + "name": "InfluxDB-Seattle", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "InfluxDB-Seattle-URL" + },{ + "id": "17", + "name": "InfluxDB-Chicago", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "InfluxDB-Chicago-URL" + }], + "id": "15", + "name": "InfluxDB", + "source": "unknown", + "type": "folder" + }, { + "children": [ { + "id": "20", + "name": "Agora Apps Repo - Microsoft", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "https://github.com/azure/jumpstart-apps" + }, { + "id": "21", + "name": "Agora-Apps-Repo-Your-Fork", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "Agora-Apps-Repo-Clone-URL" + } ], + "id": "19", + "name": "GitHub", + "source": "unknown", + "type": "folder" + }, { + "id": "22", + "name": "ADX Dashboards", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "https://dataexplorer.azure.com/dashboards/" + }, { + "id": "23", + "name": "Arc Jumpstart", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "https://aka.ms/ArcJumpstart/" + }, { + "id": "24", + "name": "Azure Portal", + "show_icon": false, + "source": "unknown", + "type": "url", + "url": "https://portal.azure.com/" + } ], + "id": "1", + "name": "Favorites bar", + "source": "unknown", + "type": "folder" + }, + "other": { + "children": [ ], + "id": "25", + "name": "Other favorites", + "source": "unknown", + "type": "folder" + }, + "synced": { + "children": [ ], + "id": "26", + "name": "Mobile favorites", + "source": "unknown", + "type": "folder" + } + }, + "version": 1 +} diff --git a/azure_jumpstart_ag/artifacts/settings/Bookmarks-manufacturing b/azure_jumpstart_ag/artifacts/settings/Bookmarks-contoso-motors similarity index 100% rename from azure_jumpstart_ag/artifacts/settings/Bookmarks-manufacturing rename to azure_jumpstart_ag/artifacts/settings/Bookmarks-contoso-motors diff --git a/azure_jumpstart_ag/artifacts/settings/Bookmarks-retail b/azure_jumpstart_ag/artifacts/settings/Bookmarks-contoso-supermarket similarity index 100% rename from azure_jumpstart_ag/artifacts/settings/Bookmarks-retail rename to azure_jumpstart_ag/artifacts/settings/Bookmarks-contoso-supermarket diff --git a/azure_jumpstart_ag/artifacts/settings/mqtt_explorer_settings_hypermarket.json b/azure_jumpstart_ag/artifacts/settings/mqtt_explorer_settings_hypermarket.json new file mode 100644 index 0000000000..f039a408ad --- /dev/null +++ b/azure_jumpstart_ag/artifacts/settings/mqtt_explorer_settings_hypermarket.json @@ -0,0 +1,34 @@ +{ + "ConnectionManager_connections": { + "mqtt.eclipse.org": { + "certValidation": false, + "clientId": "mqtt-explorer-640c948e", + "encryption": false, + "host": "seattleIpPlaceholder", + "id": "mqtt.eclipse.org", + "name": "seattle", + "port": 1883, + "protocol": "mqtt", + "subscriptions": [ + "#", + "$SYS/#" + ], + "type": "mqtt" + }, + "mqtt.eclipse.org2": { + "certValidation": false, + "clientId": "mqtt-explorer-640c948e", + "encryption": false, + "host": "chicagoIpPlaceholder", + "id": "mqtt.eclipse.org2", + "name": "chicago", + "port": 1883, + "protocol": "mqtt", + "subscriptions": [ + "#", + "$SYS/#" + ], + "type": "mqtt" + } + } +} \ No newline at end of file diff --git a/azure_jumpstart_ag/artifacts/settings/mqtt_explorer_settings.json b/azure_jumpstart_ag/artifacts/settings/mqtt_explorer_settings_motors.json similarity index 100% rename from azure_jumpstart_ag/artifacts/settings/mqtt_explorer_settings.json rename to azure_jumpstart_ag/artifacts/settings/mqtt_explorer_settings_motors.json diff --git a/azure_jumpstart_ag/artifacts/settings/mqtt_listener.yml b/azure_jumpstart_ag/artifacts/settings/mqtt_listener.yml index 5d82b71c8d..65d91e0cd4 100644 --- a/azure_jumpstart_ag/artifacts/settings/mqtt_listener.yml +++ b/azure_jumpstart_ag/artifacts/settings/mqtt_listener.yml @@ -16,7 +16,7 @@ spec: spec: containers: - name: mqtt-listener - image: jumpstartprod.azurecr.io/mqtt-listener:latest + image: jumpstartprod.azurecr.io/contoso-supermarket-mqtt-listener:latest resources: limits: memory: "512Mi" diff --git a/azure_jumpstart_ag/artifacts/settings/mqtt_simulator.yml b/azure_jumpstart_ag/artifacts/settings/mqtt_simulator.yml index 36b04431e4..de1f2fdfcc 100644 --- a/azure_jumpstart_ag/artifacts/settings/mqtt_simulator.yml +++ b/azure_jumpstart_ag/artifacts/settings/mqtt_simulator.yml @@ -14,7 +14,7 @@ spec: spec: containers: - name: mqtt-simulator - image: agoraarmbladev.azurecr.io/mqtt-simulator:latest + image: jumpstartprod.azurecr.io/contoso-supermarket-mqtt-simulator:latest resources: limits: cpu: "1" diff --git a/azure_jumpstart_ag/manufacturing/.gitignore b/azure_jumpstart_ag/contoso_hypermarket/.gitignore similarity index 100% rename from azure_jumpstart_ag/manufacturing/.gitignore rename to azure_jumpstart_ag/contoso_hypermarket/.gitignore diff --git a/azure_jumpstart_ag/manufacturing/azure.yaml b/azure_jumpstart_ag/contoso_hypermarket/azure.yaml similarity index 100% rename from azure_jumpstart_ag/manufacturing/azure.yaml rename to azure_jumpstart_ag/contoso_hypermarket/azure.yaml diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/ai/aoai.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/ai/aoai.bicep new file mode 100644 index 0000000000..a256ca4a0d --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/ai/aoai.bicep @@ -0,0 +1,63 @@ +@description('The name of the OpenAI Cognitive Services account') +param openAIAccountName string = 'openai${uniqueString(resourceGroup().id,location)}' + +@description('The location of the OpenAI Cognitive Services account') +param location string = resourceGroup().location + +@description('The name of the OpenAI Cognitive Services SKU') +param openAISkuName string = 'S0' + +@description('The capacity of the OpenAI Cognitive Services account') +param openAICapacity int = 10 + +@description('The type of Cognitive Services account to create') +param cognitiveSvcType string = 'AIServices' + +@description('The deployment type of the Cognitive Services account') +@allowed([ + 'ProvisionedManaged' + 'Standard' + 'GlobalStandard' +]) +param azureOpenAiSkuName string = 'GlobalStandard' + +@description('The array of OpenAI models to deploy') +param azureOpenAIModel object = { + name: 'gpt-4o' + version: '2024-05-13' + } + +resource openAIAccount 'Microsoft.CognitiveServices/accounts@2024-06-01-preview' = { + name: openAIAccountName + location: location + sku: { + name: openAISkuName + } + kind: cognitiveSvcType + properties: { + publicNetworkAccess: 'Enabled' + } +} + +resource openAIModelsDeployment 'Microsoft.CognitiveServices/accounts/deployments@2024-06-01-preview' = { + parent: openAIAccount + name: '${openAIAccountName}-${azureOpenAIModel.name}-deployment' + sku: { + name: azureOpenAiSkuName + capacity: openAICapacity + } + properties: { + model: { + format: 'OpenAI' + name: azureOpenAIModel.name + version: azureOpenAIModel.version + } + versionUpgradeOption: 'NoAutoUpgrade' + currentCapacity: openAICapacity + raiPolicyName: 'Microsoft.Default' + } +} + +output openAIEndpoint string = filter(items(openAIAccount.properties.endpoints), endpoint => endpoint.key == 'OpenAI Language Model Instance API')[0].value +output speechToTextEndpoint string = filter(items(openAIAccount.properties.endpoints), endpoint => endpoint.key == 'Speech Services Speech to Text (Standard)')[0].value +output openAIDeploymentName string = openAIModelsDeployment.name \ No newline at end of file diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/clientVm/clientVm.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/clientVm/clientVm.bicep new file mode 100644 index 0000000000..42cfd50d2a --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/clientVm/clientVm.bicep @@ -0,0 +1,254 @@ +@description('The name of your Virtual Machine') +param vmName string = 'Ag-VM-Client' + +@description('Username for the Virtual Machine') +param windowsAdminUsername string = 'agora' + +@description('Password for Windows account. Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. The value must be between 12 and 123 characters long') +@minLength(12) +@maxLength(123) +@secure() +param windowsAdminPassword string + +@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version') +param windowsOSVersion string = '2022-datacenter-g2' + +@description('Location for all resources') +param location string = resourceGroup().location + +@description('Enable automatic logon into Virtual Machine') +param vmAutologon bool = false + +@description('Name of the storage account') +param aioStorageAccountName string = 'aiostg${namingGuid}' + +@description('Resource tag for Jumpstart Agora') +param resourceTags object = { + Project: 'Jumpstart_Agora' +} + +@description('Resource Id of the subnet in the virtual network') +param subnetId string + +@description('Tenant id of the service principal') +param tenantId string + +@description('Name for the environment Azure Log Analytics workspace') +param workspaceName string + +@description('The base URL used for accessing artifacts and automation artifacts.') +param templateBaseUrl string + +@description('Choice to deploy Bastion to connect to the client VM') +param deployBastion bool = false + +@description('Storage account used for staging file artifacts') +param storageAccountName string + +@description('Override default RDP port using this parameter. Default is 3389. No changes will be made to the client VM.') +param rdpPort string = '3389' + +@description('Target GitHub account') +param githubAccount string = 'microsoft' + +@description('Target GitHub branch') +param githubBranch string = 'main' + +@description('Random GUID') +param namingGuid string + +@description('The custom location RPO ID') +param customLocationRPOID string + +@description('The agora scenario to be deployed') +param scenario string = 'contoso_supermarket' + +@description('The name of the Azure Arc K3s cluster') +param k3sArcDataClusterName string = 'Ag-K3s-Seattle-${namingGuid}' + +@description('The name of the Azure Arc K3s data cluster') +param k3sArcClusterName string = 'Ag-K3s-Chicago-${namingGuid}' + +@description('The URL of the Azure OpenAI endpoint.') +param openAIEndpoint string + +@description('The URL of the Speech-to-text endpoint.') +param speachToTextEndpoint string + +@description('The array of OpenAI models to deploy') +param azureOpenAIModel object = { + name: 'gpt-4o' + version: '2024-05-13' + apiVersion: '2024-08-01-preview' +} + +@description('The name of the OpenAI deployment name.') +param openAIDeploymentName string = '' + +var encodedPassword = base64(windowsAdminPassword) +var bastionName = 'Ag-Bastion' +var publicIpAddressName = deployBastion == false ? '${vmName}-PIP' : '${bastionName}-PIP' +var networkInterfaceName = '${vmName}-NIC' +var osDiskType = 'Premium_LRS' +var PublicIPNoBastion = { + id: publicIpAddress.id +} + +resource networkInterface 'Microsoft.Network/networkInterfaces@2023-02-01' = { + name: networkInterfaceName + location: location + tags: resourceTags + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: subnetId + } + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: deployBastion == false ? PublicIPNoBastion : null + } + } + ] + } +} + +resource publicIpAddress 'Microsoft.Network/publicIpAddresses@2023-02-01' = if (deployBastion == false) { + name: publicIpAddressName + location: location + tags: resourceTags + properties: { + publicIPAllocationMethod: 'Static' + publicIPAddressVersion: 'IPv4' + idleTimeoutInMinutes: 4 + } + sku: { + name: 'Basic' + } +} + +resource vm 'Microsoft.Compute/virtualMachines@2022-11-01' = { + name: vmName + location: location + tags: resourceTags + identity: { + type: 'SystemAssigned' + } + properties: { + hardwareProfile: { + vmSize: 'Standard_D8s_v5' + } + storageProfile: { + osDisk: { + name: '${vmName}-OSDisk' + caching: 'ReadWrite' + createOption: 'FromImage' + managedDisk: { + storageAccountType: osDiskType + } + diskSizeGB: 256 + } + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: windowsOSVersion + version: 'latest' + } + dataDisks: [] + } + networkProfile: { + networkInterfaces: [ + { + id: networkInterface.id + } + ] + } + osProfile: { + computerName: vmName + adminUsername: windowsAdminUsername + adminPassword: windowsAdminPassword + windowsConfiguration: { + provisionVMAgent: true + enableAutomaticUpdates: true + enableVMAgentPlatformUpdates: true + patchSettings: { + assessmentMode: 'AutomaticByPlatform' + patchMode: 'AutomaticByPlatform' + automaticByPlatformSettings: { + rebootSetting: 'Never' + } + } + } + } + } +} + +resource vmBootstrap 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = { + parent: vm + name: 'Bootstrap' + location: location + tags: { + displayName: 'config-choco' + } + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + autoUpgradeMinorVersion: true + protectedSettings: { + fileUris: [ + uri(templateBaseUrl, 'artifacts/PowerShell/Bootstrap.ps1') + ] + commandToExecute: 'powershell.exe -ExecutionPolicy Bypass -File Bootstrap.ps1 -adminUsername ${windowsAdminUsername} -adminPassword ${encodedPassword} -tenantId ${tenantId} -subscriptionId ${subscription().subscriptionId} -resourceGroup ${resourceGroup().name} -azureLocation ${location} -stagingStorageAccountName ${storageAccountName} -workspaceName ${workspaceName} -templateBaseUrl ${templateBaseUrl} -rdpPort ${rdpPort} -githubAccount ${githubAccount} -githubBranch ${githubBranch} -namingGuid ${namingGuid} -customLocationRPOID ${customLocationRPOID} -scenario ${scenario} -aioStorageAccountName ${aioStorageAccountName} -k3sArcClusterName ${k3sArcClusterName} -k3sArcDataClusterName ${k3sArcDataClusterName} -openAIEndpoint ${openAIEndpoint} -speachToTextEndpoint ${speachToTextEndpoint} -vmAutologon ${vmAutologon} -azureOpenAIModel ${azureOpenAIModel} -openAIDeploymentName ${openAIDeploymentName}' + } + } +} + +// Add role assignment for the VM: Azure Key Vault Secret Officer role +resource vmRoleAssignment_KeyVaultAdministrator 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(vm.id, 'Microsoft.Authorization/roleAssignments', 'Administrator') + scope: resourceGroup() + properties: { + principalId: vm.identity.principalId + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483') + principalType: 'ServicePrincipal' + + } +} + +// Add role assignment for the VM: Owner role +resource vmRoleAssignment_Owner 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(vm.id, 'Microsoft.Authorization/roleAssignments', 'Owner') + scope: resourceGroup() + properties: { + principalId: vm.identity.principalId + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + principalType: 'ServicePrincipal' + } +} + +// Add role assignment for the VM: Storage Blob Data Contributor +resource vmRoleAssignment_Storage 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(vm.id, 'Microsoft.Authorization/roleAssignments', 'Storage Blob Data Contributor') + scope: resourceGroup() + properties: { + principalId: vm.identity.principalId + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') + principalType: 'ServicePrincipal' + } +} + +// Add role assignment for the VM: Cognitive Services OpenAI Contributor +resource vmRoleAssignment_OpenAI 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(vm.id, 'Microsoft.Authorization/roleAssignments', 'Cognitive Services OpenAI Contributor') + scope: resourceGroup() + properties: { + principalId: vm.identity.principalId + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442') + principalType: 'ServicePrincipal' + } +} + +output adminUsername string = windowsAdminUsername +output publicIP string = deployBastion == false ? concat(publicIpAddress.properties.ipAddress) : '' diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/data/dataflows.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/data/dataflows.bicep new file mode 100644 index 0000000000..2b5be40757 --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/data/dataflows.bicep @@ -0,0 +1,98 @@ +@description('The name of the IoT Operations instance') +param aioInstanceName string + +@description('The name of the custom location') +param customLocationName string + +@description('The name of the Event Hub namespace') +param evenHubNamespaceHost string + +@description('The name of the Event Hub') +param eventHubName string + +@description('The name of the IoT data flow') +param iotDataFlowName string = 'iot-mqtt-to-eventhub' + +@description('The name of the commercial data flow') +param defaultDataflowEndpointName string = 'default' +param eventHubDataflowEndpointName string = 'eventhub-endpoint' + +resource aioInstance 'Microsoft.IoTOperations/instances@2024-11-01' existing = { + name: aioInstanceName +} + +resource customLocation 'Microsoft.ExtendedLocation/customLocations@2021-08-31-preview' existing = { + name: customLocationName +} + +resource eventhubEndpoint 'Microsoft.IoTOperations/instances/dataflowEndpoints@2024-11-01' = { + parent: aioInstance + name: eventHubDataflowEndpointName + extendedLocation: { + name: customLocation.id + type: 'CustomLocation' + } + dependsOn: [ + customLocation + ] + properties: { + endpointType: 'Kafka' + kafkaSettings: { + host: evenHubNamespaceHost + authentication: { + method: 'SystemAssignedManagedIdentity' + systemAssignedManagedIdentitySettings: {} + } + tls: { + mode: 'Enabled' + } + batching: { + latencyMs: 1000 + maxMessages: 100 + maxBytes: 1024 + } + kafkaAcks: 'All' + copyMqttProperties: 'Enabled' + consumerGroupId: 'mqConnector' + } + } +} + +// Pointer to the default dataflow profile +resource defaultDataflowProfile 'Microsoft.IoTOperations/instances/dataflowProfiles@2024-11-01' existing = { + parent: aioInstance + name: 'default' +} + +resource iotDataFlow 'Microsoft.IoTOperations/instances/dataflowProfiles/dataflows@2024-11-01' = { + // Reference to the parent dataflow profile, the default profile in this case + // Same usage as profileRef in Kubernetes YAML + parent: defaultDataflowProfile + name: iotDataFlowName + extendedLocation: { + name: customLocation.id + type: 'CustomLocation' + } + properties: { + mode: 'Enabled' + operations: [ + { + operationType: 'Source' + sourceSettings: { + endpointRef: defaultDataflowEndpointName + dataSources: [ + 'iot/#' + 'topic/#' + ] + } + } + { + operationType: 'Destination' + destinationSettings: { + endpointRef: eventHubDataflowEndpointName + dataDestination: eventHubName + } + } + ] + } +} diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/data/eventHub.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/data/eventHub.bicep new file mode 100644 index 0000000000..759731bc08 --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/data/eventHub.bicep @@ -0,0 +1,59 @@ +@description('The name of the EventHub namespace') +param eventHubNamespaceName string = 'aiohubns${uniqueString(resourceGroup().id)}' + +@description('The name of the Orders EventHub') +param eventHubName string + +@description('EventHub Sku') +param eventHubSku string = 'Standard' + +@description('EventHub Tier') +param eventHubTier string = 'Standard' + +@description('EventHub capacity') +param eventHubCapacity int = 1 + +@description('Resource tag for Jumpstart Agora') +param resourceTags object = { + Project: 'Jumpstart_azure_aio' +} + +@description('The location of the Azure Data Explorer cluster') +param location string = resourceGroup().location + +resource eventHubNamespace 'Microsoft.EventHub/namespaces@2023-01-01-preview' = { + name: eventHubNamespaceName + tags: resourceTags + location: location + sku: { + name: eventHubSku + capacity: eventHubCapacity + tier: eventHubTier + } +} + +resource eventHub 'Microsoft.EventHub/namespaces/eventhubs@2023-01-01-preview' = { + name: eventHubName + parent: eventHubNamespace + properties: { + messageRetentionInDays: 1 + } +} + +resource eventHubAuthRule 'Microsoft.EventHub/namespaces/authorizationRules@2023-01-01-preview' = { + name: 'FabricSharedAccessKey' + parent: eventHubNamespace + properties: { + rights: [ + 'Listen' + 'Send' + ] + } +} + +resource fabricCG 'Microsoft.EventHub/namespaces/eventhubs/consumergroups@2023-01-01-preview' = { + name: 'fabriccg' + parent: eventHub +} + +output eventHubResourceId string = eventHub.id diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/data/fabric.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/data/fabric.bicep new file mode 100644 index 0000000000..b5fa76a130 --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/data/fabric.bicep @@ -0,0 +1,22 @@ +@description('Microsoft Fabric capacity name') +param fabricCapacityName string = 'agorafabric' + +@description('The location of the Microsoft Fabric capacity ') +param location string = resourceGroup().location + +@description('Microsoft Fabric capacity admin email address') +param fabricCapacityAdmin string + +resource fabricCapacity 'Microsoft.Fabric/capacities@2023-11-01' = { + name: fabricCapacityName + location: location + sku: { + name: 'F2' + tier: 'Fabric' + } + properties: { + administration: { + members: [fabricCapacityAdmin] + } + } +} diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/data/keyVault.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/data/keyVault.bicep new file mode 100644 index 0000000000..63353e3d55 --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/data/keyVault.bicep @@ -0,0 +1,71 @@ +@description('Azure Key Vault name') +param akvNameSite1 string = 'aio-akv-01' + +@description('Azure Key Vault name') +param akvNameSite2 string = 'aio-akv-02' + +@description('Azure Key Vault location') +param location string = resourceGroup().location + +@description('Azure Key Vault SKU') +param akvSku string = 'standard' + +@description('Azure Key Vault tenant ID') +param tenantId string = subscription().tenantId + +@description('Secret name') +param aioPlaceHolder string = 'azure-iot-operations' + +@description('Secret value') +param aioPlaceHolderValue string = 'aioSecretValue' + +@description('Resource tag for Jumpstart Agora') +param resourceTags object = { + Project: 'Jumpstart_azure_aio' +} + +resource akv 'Microsoft.KeyVault/vaults@2023-02-01' = { + name: akvNameSite1 + location: location + tags: resourceTags + properties: { + sku: { + name: akvSku + family: 'A' + } + enableRbacAuthorization: true + enableSoftDelete: false + tenantId: tenantId + } +} + +resource aioSecretPlaceholder 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + name: aioPlaceHolder + parent: akv + properties: { + value: aioPlaceHolderValue + } +} + +resource akv2 'Microsoft.KeyVault/vaults@2023-02-01' = { + name: akvNameSite2 + location: location + tags: resourceTags + properties: { + sku: { + name: akvSku + family: 'A' + } + enableRbacAuthorization: true + enableSoftDelete: false + tenantId: tenantId + } +} + +resource aioSecretPlaceholder2 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + name: aioPlaceHolder + parent: akv2 + properties: { + value: aioPlaceHolderValue + } +} \ No newline at end of file diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/data/script.kql b/azure_jumpstart_ag/contoso_hypermarket/bicep/data/script.kql new file mode 100644 index 0000000000..9b5c84d78b --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/data/script.kql @@ -0,0 +1,142 @@ +.execute database script with (ContinueOnErrors=true) +<| + +// Check if the table exists +.drop table staging ifexists + +// Create new staging table +.create table staging (source: string, subject: string, event_data: dynamic) + +// Create staging ingestion mapping +.create table staging ingestion json mapping "staging_mapping" +``` +[ +{"column":"source","path":"$['source']","datatype":"string"}, +{"column":"subject","path":"$['subject']","datatype":"string"}, +{"column":"event_data","path":"$['event_data']","datatype":""} +] +``` + +// Modify the ingestion batching policy to ingest data frequently +.alter table staging policy ingestionbatching "{'MaximumBatchingTimeSpan': '0:01:00', 'MaximumNumberOfItems': 10000}" + +// Delete existing table +.drop table sales ifexists + +// Create sales table +.create table sales (sale_id: string, sale_date: datetime, store_id: string, store_city:string, product_id: string, product_category:string, product_name:string, price: real, discount: real, quantity: int, item_total: real, profit: real, payment_method: string, customer_id:string, register_id: string) + +// Create function to expand sales data +.create-or-alter function expand_sales_data() +{ + staging + | where subject == "topic/sales" + | extend data = parse_json(event_data) + | project + sale_id = tostring(data.sale_id), + sale_date = todatetime(data.sale_date), + store_id = tostring(data.store_id), + store_city = tostring(data.store_city), + product_id = tostring(data.product_id), + product_category = tostring(data.product_category), + product_name = tostring(data.product_name), + price = toreal(data.price), + discount = toreal(data.discount), + quantity = toint(data.quantity), + item_total = toreal(data.item_total), + profit = toreal(data.profit), + payment_method = tostring(data.payment_method), + customer_id = tostring(data.customer_id), + register_id = tostring(data.register_id) +} + +// Create policy to update sales table +.alter table sales policy update @'[{"Source": "staging", "Query": "expand_sales_data()", "IsEnabled": "True"}]' + +// Delete existing table +.drop table inventory ifexists + +// Create inventory table +.create table inventory (date_time: datetime, store_id: string, product_id: string, retail_price: real, stock_level: int, reorder_threshold: int, last_restocked: datetime) + +// Create function to expand inventory data +.create-or-alter function expand_inventory_data() +{ + staging + | where subject == "topic/inventory" + | extend data = parse_json(event_data) + | project + date_time = todatetime(data.date_time), + store_id = tostring(data.store_id), + product_id = tostring(data.product_id), + retail_price = toreal(data.retail_price), + stock_level = toint(data.in_stock), + reorder_threshold = toint(data.reorder_threshold), + last_restocked = todatetime(data.last_restocked) +} + +// Create policy +.alter table inventory policy update @'[{"Source": "staging", "Query": "expand_inventory_data()", "IsEnabled": "True"}]' + +// Create product table +.drop table products ifexists +.create table products (product_id:string, name:string, price:real, stock:int, category: string, photo_path:string) +.ingest inline into table products <| +1,Red Apple,0.2,1000,Fruits,static/img/product1.jpg +2,Banana,0.2,300,Fruits,static/img/product2.jpg +3,Avocado,1.25,1000,Vegetables,static/img/product3.jpg +4,Bread,3.0,200,Bakery,static/img/product4.jpg +5,Milk,2.5,200,Dairy,static/img/product5.jpg +6,Orange Juice,3.25,100,Fruits,static/img/product6.jpg +7,Chips,0.25,1000,Snacks,static/img/product7.jpg +8,Red Pepper,0.5,800,Vegetables,static/img/product8.jpg +9,Lettuce,0.3,2000,Vegetables,static/img/product9.jpg +10,Tomato,0.4,5000,Vegetables,static/img/product10.jpg +11,Strawberry,2.0,500,Fruits,static/img/product11.jpg +12,Eggs,3.0,10000,Poultry,static/img/product12.jpg + +// Create stores table +.drop table stores ifexists +.create table stores (store_id:string, city:string, state:string, country:string) +.ingest inline into table stores <| +CHI,Chicago,IL,United States +SEA,Seattle, WA,United States +NYC,New York, NY,United States +DAL,Dallas,TX,United States +ATL,Atlanta,GA,United States +LAS,Las Vegas,NV,United States +MIA,Miami,FL,United States +LAX,Los Angeles,CA,United States + +// Create Industrial Operations Data Tables +.drop table iot_data ifexists +.create table iot_data (timestamp: datetime, store_id: string, device_id: string, equipment_type: string, data: dynamic ) + +// Create staging ingestion mapping +.create table iot_data ingestion json mapping "iot_data_mapping" +``` +[ +{"column":"timestamp","path":"$['timestamp']","datatype":"datetime"}, +{"column":"store_id","path":"$['store_id']","datatype":"string"}, +{"column":"device_id","path":"$['device_id']","datatype":"string"}, +{"column":"equipment_type","path":"$['equipment_type']","datatype":"string"}, +{"column":"data","path":"$['data']","datatype":""} +] +``` + +// Create function to expand inventory data +.create-or-alter function expand_iot_data() +{ + staging + | where subject == "iot/devices" + | extend data = parse_json(event_data) + | project + timestamp = todatetime(data.timestamp), + store_id = tostring(data.store_id), + device_id = tostring(data.device_id), + equipment_type = tostring(data.equipment_type), + data = data.data +} + +// Create policy +.alter table iot_data policy update @'[{"Source": "staging", "Query": "expand_iot_data()", "IsEnabled": "True"}]' diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/kubernetes/ubuntuRancher.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/kubernetes/ubuntuRancher.bicep new file mode 100644 index 0000000000..a3f084e75b --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/kubernetes/ubuntuRancher.bicep @@ -0,0 +1,179 @@ +@description('The name of you Virtual Machine') +param vmName string = 'Ag-K3s-${namingGuid}' + +@description('Username for the Virtual Machine') +param adminUsername string = 'agora' + +@description('RSA public key used for securing SSH access to ArcBox resources. This parameter is only needed when deploying the DataOps or DevOps flavors.') +@secure() +param sshRSAPublicKey string = '' + +@description('The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version') +@allowed([ + '22_04-lts-gen2' +]) +param ubuntuOSVersion string = '22_04-lts-gen2' + +@description('Location for all resources.') +param azureLocation string = resourceGroup().location + +@description('The size of the VM') +param vmSize string = 'Standard_B4ms' + +@description('Resource Id of the subnet in the virtual network') +param subnetId string + +@description('Name for the staging storage account using to hold kubeconfig. This value is passed into the template as an output from mgmtStagingStorage.json') +param stagingStorageAccountName string + +@description('Name of the Log Analytics workspace used with cluster extensions') +param logAnalyticsWorkspace string + +@description('The base URL used for accessing artifacts and automation artifacts') +param templateBaseUrl string + +@description('Storage account container name for artifacts') +param storageContainerName string + +@maxLength(5) +@description('Random GUID') +param namingGuid string + +var publicIpAddressName = '${vmName}-PIP' +var networkInterfaceName = '${vmName}-NIC' +var osDiskType = 'Premium_LRS' +var k3sControlPlane = 'true' // deploy single-node k3s control plane +var diskSize = 512 +var numberOfIPAddresses = 15 // The number of IP addresses to create + +// Create multiple public IP addresses +resource publicIpAddresses 'Microsoft.Network/publicIpAddresses@2022-01-01' = [for i in range(1, numberOfIPAddresses): { + name: '${publicIpAddressName}${i}' + location: azureLocation + properties: { + publicIPAllocationMethod: 'Static' + publicIPAddressVersion: 'IPv4' + idleTimeoutInMinutes: 4 + } + sku: { + name: 'Basic' + } +}] + +// Create multiple NIC IP configurations and assign the public IP to the IP configuration +resource networkInterface 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: networkInterfaceName + location: azureLocation + properties: { + ipConfigurations: [for i in range(1, numberOfIPAddresses): { + name: 'ipconfig${i}' + properties: { + subnet: { + id: subnetId + } + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: publicIpAddresses[i-1].id + } + primary: i == 1 ? true : false + } + }] + } +} + +resource vm 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: vmName + location: azureLocation + identity: { + type: 'SystemAssigned' + } + properties: { + hardwareProfile: { + vmSize: vmSize + } + storageProfile: { + osDisk: { + name: '${vmName}-OSDisk' + caching: 'ReadWrite' + createOption: 'FromImage' + managedDisk: { + storageAccountType: osDiskType + } + diskSizeGB: diskSize + } + imageReference: { + publisher: 'canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: ubuntuOSVersion + version: 'latest' + } + } + networkProfile: { + networkInterfaces: [ + { + id: networkInterface.id + } + ] + } + osProfile: { + computerName: vmName + adminUsername: adminUsername + linuxConfiguration: { + disablePasswordAuthentication: true + ssh: { + publicKeys: [ + { + path: '/home/${adminUsername}/.ssh/authorized_keys' + keyData: sshRSAPublicKey + } + ] + } + } + } + } +} + +// Add role assignment for the VM: Owner role +resource vmRoleAssignment_Owner 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(vm.id, 'Microsoft.Authorization/roleAssignments', 'Owner') + scope: resourceGroup() + properties: { + principalId: vm.identity.principalId + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + principalType: 'ServicePrincipal' + } +} + +// Add role assignment for the VM: Storage Blob Data Contributor +resource vmRoleAssignment_Storage 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(vm.id, 'Microsoft.Authorization/roleAssignments', 'Storage Blob Data Contributor') + scope: resourceGroup() + properties: { + principalId: vm.identity.principalId + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') + principalType: 'ServicePrincipal' + } +} + +resource vmInstallscriptK3s 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + parent: vm + name: 'installscript_k3s' + location: azureLocation + properties: { + publisher: 'Microsoft.Azure.Extensions' + type: 'CustomScript' + typeHandlerVersion: '2.1' + autoUpgradeMinorVersion: true + settings: {} + protectedSettings: { + commandToExecute: 'bash installK3s.sh ${adminUsername} ${subscription().subscriptionId} ${vmName} ${azureLocation} ${stagingStorageAccountName} ${logAnalyticsWorkspace} ${templateBaseUrl} ${storageContainerName} ${k3sControlPlane} ${resourceGroup().name}' + fileUris: [ + '${templateBaseUrl}artifacts/kubernetes/K3s/installK3s.sh' + ] + } + } + dependsOn: [ + vmRoleAssignment_Owner + vmRoleAssignment_Storage + ] +} diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/kubernetes/ubuntuRancherNodes.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/kubernetes/ubuntuRancherNodes.bicep new file mode 100644 index 0000000000..043a42ded3 --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/kubernetes/ubuntuRancherNodes.bicep @@ -0,0 +1,182 @@ + +@description('The name of you Virtual Machine') +param vmName string = 'Ag-K3s-Node-${namingGuid}' + +@description('Username for the Virtual Machine') +param adminUsername string = 'agora' + +@description('RSA public key used for securing SSH access to ArcBox resources. This parameter is only needed when deploying the DataOps or DevOps flavors.') +@secure() +param sshRSAPublicKey string = '' + +@description('The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version') +@allowed([ + '22_04-lts-gen2' +]) +param ubuntuOSVersion string = '22_04-lts-gen2' + +@description('Location for all resources.') +param azureLocation string = resourceGroup().location + +@description('Resource Id of the subnet in the virtual network') +param subnetId string + +@description('Name for the staging storage account using to hold kubeconfig. This value is passed into the template as an output from mgmtStagingStorage.json') +param stagingStorageAccountName string + +@description('Name of the Log Analytics workspace used with cluster extensions') +param logAnalyticsWorkspace string + +@description('The base URL used for accessing artifacts and automation artifacts') +param templateBaseUrl string + +@description('Storage account container name for artifacts') +param storageContainerName string + +@maxLength(5) +@description('Random GUID') +param namingGuid string + +@description('Option to deploy GPU-enabled nodes for the K3s Worker nodes.') +param deployGPUNodes bool = false + +@description('The sku name of the K3s cluster worker nodes.') +@allowed([ + 'Standard_D8s_v5' + 'Standard_NV6ads_A10_v5' + 'Standard_NV4as_v4' +]) +param k8sWorkerNodesSku string = deployGPUNodes ? 'Standard_NV4as_v4' : 'Standard_D8s_v5' + +var networkInterfaceName = '${vmName}-NIC' +var osDiskType = 'Premium_LRS' +var diskSize = 512 + +resource networkInterface 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: networkInterfaceName + location: azureLocation + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: subnetId + } + privateIPAllocationMethod: 'Dynamic' + } + } + ] + } +} + +resource vm 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: vmName + location: azureLocation + identity: { + type: 'SystemAssigned' + } + properties: { + hardwareProfile: { + vmSize: k8sWorkerNodesSku + } + storageProfile: { + osDisk: { + name: '${vmName}-OSDisk' + caching: 'ReadWrite' + createOption: 'FromImage' + managedDisk: { + storageAccountType: osDiskType + } + diskSizeGB: diskSize + } + imageReference: { + publisher: 'canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: ubuntuOSVersion + version: 'latest' + } + } + networkProfile: { + networkInterfaces: [ + { + id: networkInterface.id + } + ] + } + osProfile: { + computerName: vmName + adminUsername: adminUsername + linuxConfiguration: { + disablePasswordAuthentication: true + ssh: { + publicKeys: [ + { + path: '/home/${adminUsername}/.ssh/authorized_keys' + keyData: sshRSAPublicKey + } + ] + } + } + } + } +} + +// Add role assignment for the VM: Owner role +resource vmRoleAssignment_Owner 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(vm.id, 'Microsoft.Authorization/roleAssignments', 'Owner') + scope: resourceGroup() + properties: { + principalId: vm.identity.principalId + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + principalType: 'ServicePrincipal' + } +} + +// Add role assignment for the VM: Storage Blob Data Contributor +resource vmRoleAssignment_Storage 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(vm.id, 'Microsoft.Authorization/roleAssignments', 'Storage Blob Data Contributor') + scope: resourceGroup() + properties: { + principalId: vm.identity.principalId + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') + principalType: 'ServicePrincipal' + } +} + +resource vmInstallscriptK3s 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + parent: vm + name: 'installscript_k3s' + location: azureLocation + properties: { + publisher: 'Microsoft.Azure.Extensions' + type: 'CustomScript' + typeHandlerVersion: '2.1' + autoUpgradeMinorVersion: true + settings: {} + protectedSettings: { + commandToExecute: 'bash installK3s.sh ${adminUsername} ${subscription().subscriptionId} ${vmName} ${azureLocation} ${stagingStorageAccountName} ${logAnalyticsWorkspace} ${templateBaseUrl} ${storageContainerName} ${deployGPUNodes}' + fileUris: [ + '${templateBaseUrl}artifacts/kubernetes/K3s/installK3s.sh' + ] + } + } + dependsOn: [ + vmRoleAssignment_Owner + vmRoleAssignment_Storage + gpuInstallationScript + ] +} + +resource gpuInstallationScript 'Microsoft.Compute/virtualMachines/extensions@2015-06-15' =if(deployGPUNodes) { + parent: vm + name: 'gpuInstallationScript' + location: azureLocation + properties: { + publisher: 'Microsoft.HpcCompute' + type: 'NvidiaGpuDriverLinux' + typeHandlerVersion: '1.6' + autoUpgradeMinorVersion: true + settings: {} + } +} diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/main.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/main.bicep new file mode 100644 index 0000000000..e9c44bfc83 --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/main.bicep @@ -0,0 +1,282 @@ +@description('Azure AD tenant id for your service principal') +param tenantId string + +@description('Location for all resources') +param location string = resourceGroup().location + +@maxLength(5) +@description('Random GUID') +param namingGuid string = toLower(substring(newGuid(), 0, 5)) + +@description('Username for Windows account') +param windowsAdminUsername string + +@description('Password for Windows account. Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. The value must be between 12 and 123 characters long') +@minLength(12) +@maxLength(123) +@secure() +param windowsAdminPassword string + +@description('Configure all linux machines with the SSH RSA public key string. Your key should include three parts, for example \'ssh-rsa AAAAB...snip...UcyupgH azureuser@linuxvm\'') +param sshRSAPublicKey string + +@description('Name for your log analytics workspace') +param logAnalyticsWorkspaceName string = 'Ag-Workspace-${namingGuid}' + +@description('Target GitHub account') +param githubAccount string = 'microsoft' + +@description('Target GitHub branch') +param githubBranch string = 'main' + +@description('Choice to deploy Bastion to connect to the client VM') +param deployBastion bool = false + +@description('Name of the Cloud VNet') +param virtualNetworkNameCloud string = 'Ag-Vnet-Prod' + +@description('Name of the Staging AKS subnet in the cloud virtual network') +param subnetNameCloudK3s string = 'Ag-Subnet-K3s' + +@description('Name of the inner-loop AKS subnet in the cloud virtual network') +param subnetNameCloud string = 'Ag-Subnet-Cloud' + +@description('Name of the storage queue') +param storageQueueName string = 'aioqueue' + +@description('Name of the event hub') +param eventHubName string = 'aiohub${namingGuid}' + +@description('Name of the event hub namespace') +param eventHubNamespaceName string = 'aiohubns${namingGuid}' + +@description('Name of the Fabric Capacity') +param fabricCapacityName string = 'agfabric${namingGuid}' + +@description('The administrator for the Microsoft Fabric capacity') +param fabricCapacityAdmin string + +@description('Name of the storage account') +param aioStorageAccountName string = 'aiostg${namingGuid}' + +@description('The custom location RPO ID') +param customLocationRPOID string + +@description('Override default RDP port using this parameter. Default is 3389. No changes will be made to the client VM.') +param rdpPort string = '3389' + +@description('Enable automatic logon into Virtual Machine') +param vmAutologon bool = true + +@description('The agora scenario to be deployed') +param scenario string = 'contoso_hypermarket' + +@description('The name of the Azure Arc K3s cluster') +param k3sArcDataClusterName string = 'Ag-K3s-Seattle-${namingGuid}' + +@description('The name of the Azure Arc K3s data cluster') +param k3sArcClusterName string = 'Ag-K3s-Chicago-${namingGuid}' + +@description('The name of the Key Vault for site 1') +param akvNameSite1 string = 'agakv1${namingGuid}' + +@description('The name of the Key Vault for site 2') +param akvNameSite2 string = 'agakv2${namingGuid}' + +@description('The capacity of the OpenAI Cognitive Services account') +param openAICapacity int = 10 + +@description('The array of OpenAI models to deploy') +param azureOpenAIModel object = { + name: 'gpt-4o' + version: '2024-05-13' + apiVersion: '2024-08-01-preview' +} + +// @description('Option to deploy GPU-enabled nodes for the K3s Worker nodes.') +// param deployGPUNodes bool = false + +@description('The sku name of the K3s cluster worker nodes.') +@allowed([ + 'Standard_D8s_v5' + 'Standard_NV6ads_A10_v5' + 'Standard_NV4as_v4' +]) +param k8sWorkerNodesSku string = 'Standard_D8s_v5' +//param k8sWorkerNodesSku string = deployGPUNodes ? 'Standard_NV4as_v4' : 'Standard_D8s_v5' + +var templateBaseUrl = 'https://raw.githubusercontent.com/${githubAccount}/azure_arc/${githubBranch}/azure_jumpstart_ag/' +var k3sClusterNodesCount = 2 // Number of nodes to deploy in the K3s cluster + +module mgmtArtifactsAndPolicyDeployment 'mgmt/mgmtArtifacts.bicep' = { + name: 'mgmtArtifactsAndPolicyDeployment' + params: { + workspaceName: logAnalyticsWorkspaceName + location: location + } +} + +module networkDeployment 'mgmt/network.bicep' = { + name: 'networkDeployment' + params: { + virtualNetworkNameCloud: virtualNetworkNameCloud + subnetNameCloudK3s: subnetNameCloudK3s + subnetNameCloud: subnetNameCloud + deployBastion: deployBastion + location: location + } +} + +module storageAccountDeployment 'mgmt/storageAccount.bicep' = { + name: 'storageAccountDeployment' + params: { + location: location + } +} + +module ubuntuRancherK3sDataSvcDeployment 'kubernetes/ubuntuRancher.bicep' = { + name: 'ubuntuRancherK3s2Deployment' + params: { + sshRSAPublicKey: sshRSAPublicKey + stagingStorageAccountName: toLower(storageAccountDeployment.outputs.storageAccountName) + logAnalyticsWorkspace: logAnalyticsWorkspaceName + templateBaseUrl: templateBaseUrl + subnetId: networkDeployment.outputs.k3sSubnetId + azureLocation: location + vmName : k3sArcDataClusterName + storageContainerName: toLower(k3sArcDataClusterName) + namingGuid: namingGuid + } +} + +module ubuntuRancherK3sDeployment 'kubernetes/ubuntuRancher.bicep' = { + name: 'ubuntuRancherK3sDeployment' + params: { + sshRSAPublicKey: sshRSAPublicKey + stagingStorageAccountName: toLower(storageAccountDeployment.outputs.storageAccountName) + logAnalyticsWorkspace: logAnalyticsWorkspaceName + templateBaseUrl: templateBaseUrl + subnetId: networkDeployment.outputs.k3sSubnetId + azureLocation: location + vmName : k3sArcClusterName + storageContainerName: toLower(k3sArcClusterName) + namingGuid: namingGuid + } +} + +module ubuntuRancherK3sDataSvcNodesDeployment 'kubernetes/ubuntuRancherNodes.bicep' = [for i in range(0, k3sClusterNodesCount): { + name: 'ubuntuRancherK3sNodesDeployment-${i}' + params: { + sshRSAPublicKey: sshRSAPublicKey + stagingStorageAccountName: toLower(storageAccountDeployment.outputs.storageAccountName) + logAnalyticsWorkspace: logAnalyticsWorkspaceName + templateBaseUrl: templateBaseUrl + subnetId: networkDeployment.outputs.k3sSubnetId + azureLocation: location + vmName : '${k3sArcDataClusterName}-Node-0${i}' + storageContainerName: toLower(k3sArcDataClusterName) + namingGuid: namingGuid + //deployGPUNodes: deployGPUNodes + k8sWorkerNodesSku: k8sWorkerNodesSku + } + dependsOn: [ + ubuntuRancherK3sDataSvcDeployment + ] +}] + +module ubuntuRancherK3sNodesDeployment 'kubernetes/ubuntuRancherNodes.bicep' = [for i in range(0, k3sClusterNodesCount): { + name: 'ubuntuRancherK3sNodes2Deployment-${i}' + params: { + sshRSAPublicKey: sshRSAPublicKey + stagingStorageAccountName: toLower(storageAccountDeployment.outputs.storageAccountName) + logAnalyticsWorkspace: logAnalyticsWorkspaceName + templateBaseUrl: templateBaseUrl + subnetId: networkDeployment.outputs.k3sSubnetId + azureLocation: location + vmName : '${k3sArcClusterName}-Node-0${i}' + storageContainerName: toLower(k3sArcClusterName) + namingGuid: namingGuid + //deployGPUNodes: deployGPUNodes + k8sWorkerNodesSku: k8sWorkerNodesSku + } + dependsOn: [ + ubuntuRancherK3sDeployment + ] +}] + +module clientVmDeployment 'clientVm/clientVm.bicep' = { + name: 'clientVmDeployment' + dependsOn: [ + ubuntuRancherK3sNodesDeployment + ubuntuRancherK3sDataSvcNodesDeployment + ] + params: { + windowsAdminUsername: windowsAdminUsername + windowsAdminPassword: windowsAdminPassword + tenantId: tenantId + workspaceName: logAnalyticsWorkspaceName + storageAccountName: storageAccountDeployment.outputs.storageAccountName + templateBaseUrl: templateBaseUrl + deployBastion: deployBastion + githubAccount: githubAccount + githubBranch: githubBranch + location: location + subnetId: networkDeployment.outputs.cloudSubnetId + rdpPort: rdpPort + namingGuid: namingGuid + scenario: scenario + customLocationRPOID: customLocationRPOID + k3sArcClusterName: k3sArcClusterName + k3sArcDataClusterName: k3sArcDataClusterName + vmAutologon: vmAutologon + openAIEndpoint: azureOpenAI.outputs.openAIEndpoint + speachToTextEndpoint: azureOpenAI.outputs.speechToTextEndpoint + azureOpenAIModel: azureOpenAIModel + openAIDeploymentName: azureOpenAI.outputs.openAIDeploymentName + } +} +module keyVault 'data/keyVault.bicep' = { + name: 'keyVaultDeployment' + params: { + tenantId: tenantId + akvNameSite1: akvNameSite1 + akvNameSite2: akvNameSite2 + location: location + } +} + +module storageAccount 'storage/storageAccount.bicep' = { + name: 'aioStorageAccountDeployment' + params: { + storageAccountName: aioStorageAccountName + location: location + storageQueueName: storageQueueName + } +} + +module eventHub 'data/eventHub.bicep' = { + name: 'eventHubDeployment' + params: { + eventHubName: eventHubName + eventHubNamespaceName: eventHubNamespaceName + location: location + } +} + +module fabricCapacity 'data/fabric.bicep' = if (!empty(fabricCapacityAdmin)) { + name: 'fabricCapacity' + params: { + fabricCapacityName: fabricCapacityName + fabricCapacityAdmin: fabricCapacityAdmin + } +} + +module azureOpenAI 'ai/aoai.bicep' = { + name: 'azureOpenAIDeployment' + params: { + location: location + openAIAccountName: 'openai${namingGuid}' + azureOpenAIModel: azureOpenAIModel + openAICapacity: openAICapacity + } +} diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/main.bicepparam b/azure_jumpstart_ag/contoso_hypermarket/bicep/main.bicepparam new file mode 100644 index 0000000000..e2b99eb3e8 --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/main.bicepparam @@ -0,0 +1,9 @@ +using 'main.bicep' + +param tenantId = '' +param windowsAdminUsername = 'agora' +param windowsAdminPassword = 'ArcPassword123!!' +param deployBastion = false +param customLocationRPOID = '' +param sshRSAPublicKey = '' +param fabricCapacityAdmin = '' diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/main.parameters.json b/azure_jumpstart_ag/contoso_hypermarket/bicep/main.parameters.json new file mode 100644 index 0000000000..615c502002 --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/main.parameters.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "tenantId": { + "value": "" + }, + "windowsAdminUsername": { + "value": "agora" + }, + "windowsAdminPassword": { + "value": "ArcPassword123!!" + }, + "deployBastion": { + "value": false + }, + "customLocationRPOID": { + "value": "" + }, + "sshRSAPublicKey": { + "value": "" + }, + "fabricCapacityAdmin": { + "value": "" + }, + "deployGPUNodes": { + "value": "false" + } + } +} diff --git a/azure_jumpstart_ag/retail/bicep/mgmt/mgmtArtifacts.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/mgmtArtifacts.bicep similarity index 100% rename from azure_jumpstart_ag/retail/bicep/mgmt/mgmtArtifacts.bicep rename to azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/mgmtArtifacts.bicep diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/network.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/network.bicep new file mode 100644 index 0000000000..d1b68a748d --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/network.bicep @@ -0,0 +1,425 @@ +@description('Name of the Cloud VNet') +param virtualNetworkNameCloud string + +@description('Name of the K3s subnet in the cloud virtual network') +param subnetNameCloudK3s string + +@description('Name of the inner-loop subnet in the cloud virtual network') +param subnetNameCloud string + +@description('Azure Region to deploy the Log Analytics Workspace') +param location string = resourceGroup().location + +@description('Resource tag for Jumpstart Agora') +param resourceTags object = { + Project: 'Jumpstart_Agora' +} + +@description('Choice to deploy Bastion to connect to the client VM') +param deployBastion bool = false + +@description('Name of the prod Network Security Group') +param networkSecurityGroupNameCloud string = 'Ag-NSG-Prod' + +@description('Name of the Bastion Network Security Group') +param bastionNetworkSecurityGroupName string = 'Ag-NSG-Bastion' + +var addressPrefixCloud = '10.16.0.0/16' +var subnetAddressPrefixK3s = '10.16.80.0/21' +var subnetAddressPrefixCloud = '10.16.64.0/21' +var bastionSubnetIpPrefix = '10.16.3.64/26' +var bastionSubnetName = 'AzureBastionSubnet' +var bastionSubnetRef = '${cloudVirtualNetwork.id}/subnets/${bastionSubnetName}' +var bastionName = 'Ag-Bastion' +var bastionPublicIpAddressName = '${bastionName}-PIP' +var sites = [ + 'Chicago' + 'Seattle' +] + +var bastionSubnet = [ + { + name: 'AzureBastionSubnet' + properties: { + addressPrefix: bastionSubnetIpPrefix + networkSecurityGroup: { + id: bastionNetworkSecurityGroup.id + } + } + } +] +var cloudK3sSubnet = [ + { + name: subnetNameCloudK3s + properties: { + addressPrefix: subnetAddressPrefixK3s + privateEndpointNetworkPolicies: 'Enabled' + privateLinkServiceNetworkPolicies: 'Enabled' + networkSecurityGroup: { + id: networkSecurityGroupCloud.id + } + } + } +] + +var cloudSubnet = [ + { + name: subnetNameCloud + properties: { + addressPrefix: subnetAddressPrefixCloud + privateEndpointNetworkPolicies: 'Enabled' + privateLinkServiceNetworkPolicies: 'Enabled' + networkSecurityGroup: { + id: networkSecurityGroupCloud.id + } + } + } +] + +resource cloudVirtualNetwork 'Microsoft.Network/virtualNetworks@2022-07-01' = { + name: virtualNetworkNameCloud + location: location + tags: resourceTags + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefixCloud + ] + } + subnets: (deployBastion == false) + ? union(cloudK3sSubnet, cloudSubnet) + : union(cloudK3sSubnet, cloudSubnet, bastionSubnet) + } +} + +resource publicIpAddress 'Microsoft.Network/publicIPAddresses@2023-02-01' = if (deployBastion == true) { + name: bastionPublicIpAddressName + location: location + tags: resourceTags + properties: { + publicIPAllocationMethod: 'Static' + publicIPAddressVersion: 'IPv4' + idleTimeoutInMinutes: 4 + } + sku: { + name: 'Standard' + } +} + +resource networkSecurityGroupCloud 'Microsoft.Network/networkSecurityGroups@2023-02-01' = { + name: networkSecurityGroupNameCloud + location: location + tags: resourceTags + properties: { + securityRules: [ + { + name: 'allow_k8s_80' + properties: { + priority: 1000 + protocol: 'TCP' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '80' + } + } + { + name: 'allow_k8s_8080' + properties: { + priority: 1010 + protocol: 'TCP' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '8080' + } + } + { + name: 'allow_k8s_443' + properties: { + priority: 1020 + protocol: 'TCP' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'allow_prometheus_9090' + properties: { + priority: 1030 + protocol: 'TCP' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '9090' + } + } + { + name: 'allow_MQ_8883' + properties: { + priority: 1040 + protocol: 'TCP' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '8883' + } + } + { + name: 'allow_MQ_1883' + properties: { + priority: 1050 + protocol: 'TCP' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '1883' + } + } + { + name: 'allow_k8s_kubelet' + properties: { + priority: 1060 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '10250' + } + } + { + name: 'allow_traefik_lb_external' + properties: { + priority: 1070 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '32323' + } + } + { + name: 'allow_external_agora_traffic' + properties: { + priority: 1080 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '5000-5003' + '8001' + '3000' + '8086' + ] + } + } + ] + } +} + +resource bastionNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-02-01' = if (deployBastion == true) { + name: bastionNetworkSecurityGroupName + location: location + tags: resourceTags + properties: { + securityRules: [ + { + name: 'bastion_allow_https_inbound' + properties: { + priority: 1010 + protocol: 'TCP' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'Internet' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'bastion_allow_gateway_manager_inbound' + properties: { + priority: 1011 + protocol: 'TCP' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'GatewayManager' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'bastion_allow_load_balancer_inbound' + properties: { + priority: 1012 + protocol: 'TCP' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'AzureLoadBalancer' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'bastion_allow_host_comms' + properties: { + priority: 1013 + protocol: '*' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'bastion_allow_ssh_rdp_outbound' + properties: { + priority: 1014 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '22' + '3389' + ] + } + } + { + name: 'bastion_allow_azure_cloud_outbound' + properties: { + priority: 1015 + protocol: 'TCP' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + } + } + { + name: 'bastion_allow_bastion_comms' + properties: { + priority: 1016 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'bastion_allow_get_session_info' + properties: { + priority: 1017 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'Internet' + destinationPortRanges: [ + '80' + '443' + ] + } + } + ] + } +} + +resource bastionHost 'Microsoft.Network/bastionHosts@2023-02-01' = if (deployBastion == true) { + name: bastionName + location: location + tags: resourceTags + properties: { + ipConfigurations: [ + { + name: 'IpConf' + properties: { + publicIPAddress: { + id: publicIpAddress.id + } + subnet: { + id: bastionSubnetRef + } + } + } + ] + } +} + +resource loadBalancerPip 'Microsoft.Network/publicIPAddresses@2024-01-01' = [for (site, i) in sites: { + name: 'Ag-LB-Public-IP-${site}' + location: location + properties: { + publicIPAllocationMethod: 'Static' + publicIPAddressVersion: 'IPv4' + idleTimeoutInMinutes: 4 + } + sku: { + name: 'Standard' + } +}] + +resource loadBalancer 'Microsoft.Network/loadBalancers@2024-01-01' = [for (site, i) in sites: { + name: 'Ag-LoadBalancer-${site}' + location: location + sku: { + name: 'Standard' + } + properties: { + frontendIPConfigurations: [ + { + name: 'Ag-LB-Frontend-${site}' + properties: { + publicIPAddress: { + id: loadBalancerPip[i].id + } + } + } + ] + } +}] + + +output vnetId string = cloudVirtualNetwork.id +output k3sSubnetId string = cloudVirtualNetwork.properties.subnets[0].id +output cloudSubnetId string = cloudVirtualNetwork.properties.subnets[1].id +output virtualNetworkNameCloud string = cloudVirtualNetwork.name \ No newline at end of file diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/policyAzureArcRGScope.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/policyAzureArcRGScope.bicep new file mode 100644 index 0000000000..150db6250c --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/policyAzureArcRGScope.bicep @@ -0,0 +1,125 @@ +@description('Location of your Azure resources') +param azureLocation string + +@description('Name of your log analytics workspace') +param logAnalyticsWorkspaceId string + +var policies = [ + { + name: '(Ag) Enable Azure Monitor for Hybrid VMs with AMA' + definitionId: '/providers/Microsoft.Authorization/policySetDefinitions/59e9c3eb-d8df-473b-8059-23fd38ddd0f0' + roleDefinition: [ + '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293' + '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/cd570a14-e51a-42ad-bac8-bafd67325302' + '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa' + ] + scope: resourceGroup().id + parameters: { + logAnalyticsWorkspace: { + value: logAnalyticsWorkspaceId + } + enableProcessesAndDependencies: { + value: true + } + } + } + { + name: '(Ag) Deploy Azure Security agent on Windows Arc machines' + definitionId: '/providers/Microsoft.Authorization/policyDefinitions/d01f3018-de9f-4d75-8dae-d12c1875da9f' + roleDefinition: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293' + parameters: {} + } + { + name: '(Ag) Deploy Azure Security agent on Linux Arc machines' + definitionId: '/providers/Microsoft.Authorization/policyDefinitions/2f47ec78-4301-4655-b78e-b29377030cdc' + roleDefinition: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293' + parameters: {} + } + { + name: '(Ag) Deploy MDE agent on Windows Arc machines' + definitionId: '/providers/Microsoft.Authorization/policyDefinitions/37c043a6-6d64-656d-6465-b362dfeb354a' + roleDefinition: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + parameters: {} + } + { + name: '(Ag) Deploy MDE agent on Linux Arc machines' + definitionId: '/providers/Microsoft.Authorization/policyDefinitions/4eb909e7-6d64-656d-6465-2eeb297a1625' + roleDefinition: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + parameters: {} + } +] + +resource policies_name 'Microsoft.Authorization/policyAssignments@2022-06-01' = [for item in policies: { + name: item.name + location: azureLocation + identity: { + type: 'SystemAssigned' + } + properties: { + policyDefinitionId: any(item.definitionId) + parameters: item.parameters + } +}] + +resource policy_AMA_role_0 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid( policies[0].name, policies[0].roleDefinition[0],resourceGroup().id) + properties: { + roleDefinitionId: any(policies[0].roleDefinition[0]) + principalId: policies_name[0].identity.principalId + principalType: 'ServicePrincipal' + } +} + +resource policy_AMA_role_1 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid( policies[0].name, policies[0].roleDefinition[1],resourceGroup().id) + properties: { + roleDefinitionId: any(policies[0].roleDefinition[1]) + principalId: policies_name[0].identity.principalId + principalType: 'ServicePrincipal' + } +} + +resource policy_AMA_role_2 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid( policies[0].name, policies[0].roleDefinition[2],resourceGroup().id) + properties: { + roleDefinitionId: any(policies[0].roleDefinition[2]) + principalId: policies_name[0].identity.principalId + principalType: 'ServicePrincipal' + } +} + +resource policy_arc_windows_azure_security_agent 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid( policies[1].name, policies[1].roleDefinition,resourceGroup().id) + properties: { + roleDefinitionId: any(policies[1].roleDefinition) + principalId: policies_name[1].identity.principalId + principalType: 'ServicePrincipal' + } +} + +resource policy_arc_linux_azure_security_agent 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid( policies[2].name, policies[2].roleDefinition,resourceGroup().id) + properties: { + roleDefinitionId: any(policies[2].roleDefinition) + principalId: policies_name[2].identity.principalId + principalType: 'ServicePrincipal' + } +} + +resource policy_arc_windows_mde 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid( policies[3].name, policies[3].roleDefinition,resourceGroup().id) + properties: { + roleDefinitionId: any(policies[3].roleDefinition) + principalId: policies_name[3].identity.principalId + principalType: 'ServicePrincipal' + } +} + +resource policy_arc_linux_mde 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid( policies[4].name, policies[4].roleDefinition,resourceGroup().id) + properties: { + roleDefinitionId: any(policies[4].roleDefinition) + principalId: policies_name[4].identity.principalId + principalType: 'ServicePrincipal' + } +} diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/storageAccount.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/storageAccount.bicep new file mode 100644 index 0000000000..ad1addf2f3 --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/mgmt/storageAccount.bicep @@ -0,0 +1,51 @@ +@description('Storage Account type') +@allowed([ + 'Standard_LRS' + 'Standard_GRS' + 'Standard_ZRS' + 'Premium_LRS' +]) +param storageAccountType string = 'Standard_LRS' + +@description('Location for all resources.') +param location string = resourceGroup().location + +@description('Resource tag for Jumpstart Agora') +param resourceTags object = { + Project: 'Jumpstart_Agora' +} + +//@description('Azure service principal object id') +//param spnObjectId string + +var storageAccountName = 'agora${uniqueString(resourceGroup().id)}' + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: storageAccountName + location: location + tags: resourceTags + sku: { + name: storageAccountType + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + allowBlobPublicAccess: true + } +} + +// Add role assignment for the SPN: Storage Blob Data Contributo +/*resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(spnObjectId, resourceGroup().id, 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') + scope: resourceGroup() + properties: { + principalId: spnObjectId + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') + principalType: 'ServicePrincipal' + + } +}*/ + + +output storageAccountName string = storageAccountName +output storageAccountResourceId string = storageAccount.id diff --git a/azure_jumpstart_ag/contoso_hypermarket/bicep/storage/storageAccount.bicep b/azure_jumpstart_ag/contoso_hypermarket/bicep/storage/storageAccount.bicep new file mode 100644 index 0000000000..4b07c59713 --- /dev/null +++ b/azure_jumpstart_ag/contoso_hypermarket/bicep/storage/storageAccount.bicep @@ -0,0 +1,39 @@ +@description('Storage account name') +param storageAccountName string + +@description('Storage account location') +param location string = resourceGroup().location + +@description('Storage account kind') +param kind string = 'StorageV2' + +@description('Storage account sku') +param skuName string = 'Standard_LRS' + +param storageQueueName string = 'aioQueue' + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { + name: storageAccountName + location: location + kind: kind + sku: { + name: skuName + } + properties: { + supportsHttpsTrafficOnly: true + isHnsEnabled: true + } +} + +resource storageQueueServices 'Microsoft.Storage/storageAccounts/queueServices@2023-01-01' = { + parent: storageAccount + name: 'default' +} + +resource storageQueue 'Microsoft.Storage/storageAccounts/queueServices/queues@2023-01-01' = { + parent: storageQueueServices + name: storageQueueName +} + +output queueName string = storageQueueName +output storageAccountResourceId string = storageAccount.id diff --git a/azure_jumpstart_ag/retail/scripts/postprovision.ps1 b/azure_jumpstart_ag/contoso_hypermarket/scripts/postprovision.ps1 similarity index 96% rename from azure_jumpstart_ag/retail/scripts/postprovision.ps1 rename to azure_jumpstart_ag/contoso_hypermarket/scripts/postprovision.ps1 index 08698e13d0..752d7b163f 100644 --- a/azure_jumpstart_ag/retail/scripts/postprovision.ps1 +++ b/azure_jumpstart_ag/contoso_hypermarket/scripts/postprovision.ps1 @@ -7,7 +7,7 @@ if ($null -ne $env:AZURE_RESOURCE_GROUP){ # This section is for testing only $resourceGroup = "charris-js-ag-43-rg" $adxClusterName = "agadx2827a" - Get-AzSubscription -SubscriptionName "Arc Jumpstart Subscription" | Select-AzSubscription + Get-AzSubscription -SubscriptionName "Azure Arc Jumpstart Subscription" | Select-AzSubscription } ######################################################################## @@ -21,7 +21,7 @@ $kustoCluster = Get-AzKustoCluster -ResourceGroupName $resourceGroup -Name $adxC $adxEndPoint = $kustoCluster.Uri # Update the dashboards files with the new ADX cluster name and URI -$templateBaseUrl = "https://raw.githubusercontent.com/microsoft/azure_arc/main/azure_jumpstart_ag/retail/" +$templateBaseUrl = "https://raw.githubusercontent.com/microsoft/azure_arc/main/azure_jumpstart_ag/contoso_hypermarket/" $ordersDashboardBody = (Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/adx_dashboards/adx-dashboard-orders-payload.json").Content -replace '{{ADX_CLUSTER_URI}}', $adxEndPoint -replace '{{ADX_CLUSTER_NAME}}', $adxClusterName $iotSensorsDashboardBody = (Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/adx_dashboards/adx-dashboard-iotsensor-payload.json") -replace '{{ADX_CLUSTER_URI}}', $adxEndPoint -replace '{{ADX_CLUSTER_NAME}}', $adxClusterName diff --git a/azure_jumpstart_ag/retail/scripts/preprovision.ps1 b/azure_jumpstart_ag/contoso_hypermarket/scripts/preprovision.ps1 similarity index 100% rename from azure_jumpstart_ag/retail/scripts/preprovision.ps1 rename to azure_jumpstart_ag/contoso_hypermarket/scripts/preprovision.ps1 diff --git a/azure_jumpstart_ag/retail/.gitignore b/azure_jumpstart_ag/contoso_motors/.gitignore similarity index 100% rename from azure_jumpstart_ag/retail/.gitignore rename to azure_jumpstart_ag/contoso_motors/.gitignore diff --git a/azure_jumpstart_ag/retail/azure.yaml b/azure_jumpstart_ag/contoso_motors/azure.yaml similarity index 100% rename from azure_jumpstart_ag/retail/azure.yaml rename to azure_jumpstart_ag/contoso_motors/azure.yaml diff --git a/azure_jumpstart_ag/manufacturing/bicep/clientVm/clientVm.bicep b/azure_jumpstart_ag/contoso_motors/bicep/clientVm/clientVm.bicep similarity index 90% rename from azure_jumpstart_ag/manufacturing/bicep/clientVm/clientVm.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/clientVm/clientVm.bicep index fb4816bd52..4ab4bf32f1 100644 --- a/azure_jumpstart_ag/manufacturing/bicep/clientVm/clientVm.bicep +++ b/azure_jumpstart_ag/contoso_motors/bicep/clientVm/clientVm.bicep @@ -16,6 +16,8 @@ param windowsOSVersion string = '2022-datacenter-g2' @description('Location for all resources') param location string = resourceGroup().location +@description('Enable automatic logon into Virtual Machine') +param vmAutologon bool = false @description('Name of the storage account') param aioStorageAccountName string = 'aiostg${namingGuid}' @@ -54,9 +56,6 @@ param deployBastion bool = false @description('Storage account used for staging file artifacts') param storageAccountName string -@description('The name of ESA container in Storage Account') -param stcontainerName string - @description('The login server name of the Azure Container Registry') param acrName string @@ -82,11 +81,8 @@ param namingGuid string @description('The custom location RPO ID') param customLocationRPOID string -@description('The agora industry to be deployed') -param industry string = 'retail' - -@description('The AKS Edge Essentials schema version to be used. This is only used to pin the AKS Edge Essentials schema version for testing.') -param AKSEEPinnedSchemaVersion string = 'useLatest' +@description('The agora scenario to be deployed') +param scenario string = 'contoso_motors' var encodedPassword = base64(windowsAdminPassword) var bastionName = 'Ag-Bastion' @@ -180,7 +176,15 @@ resource vm 'Microsoft.Compute/virtualMachines@2022-11-01' = { adminPassword: windowsAdminPassword windowsConfiguration: { provisionVMAgent: true - enableAutomaticUpdates: false + enableAutomaticUpdates: true + enableVMAgentPlatformUpdates: true + patchSettings: { + assessmentMode: 'AutomaticByPlatform' + patchMode: 'AutomaticByPlatform' + automaticByPlatformSettings: { + rebootSetting: 'Never' + } + } } } } @@ -202,7 +206,7 @@ resource vmBootstrap 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = fileUris: [ uri(templateBaseUrl, 'artifacts/PowerShell/Bootstrap.ps1') ] - commandToExecute: 'powershell.exe -ExecutionPolicy Bypass -File Bootstrap.ps1 -adminUsername ${windowsAdminUsername} -adminPassword ${encodedPassword} -spnClientId ${spnClientId} -spnClientSecret ${spnClientSecret} -spnObjectId ${spnObjectId} -spnTenantId ${spnTenantId} -spnAuthority ${spnAuthority} -subscriptionId ${subscription().subscriptionId} -resourceGroup ${resourceGroup().name} -azureLocation ${location} -stagingStorageAccountName ${storageAccountName} -workspaceName ${workspaceName} -templateBaseUrl ${templateBaseUrl} -acrName ${acrName} -rdpPort ${rdpPort} -githubAccount ${githubAccount} -githubBranch ${githubBranch} -namingGuid ${namingGuid} -adxClusterName ${adxClusterName} -customLocationRPOID ${customLocationRPOID} -industry ${industry} -aioStorageAccountName ${aioStorageAccountName} -stcontainerName ${stcontainerName} -AKSEEPinnedSchemaVersion ${AKSEEPinnedSchemaVersion}' + commandToExecute: 'powershell.exe -ExecutionPolicy Bypass -File Bootstrap.ps1 -adminUsername ${windowsAdminUsername} -adminPassword ${encodedPassword} -spnClientId ${spnClientId} -spnClientSecret ${spnClientSecret} -spnObjectId ${spnObjectId} -spnTenantId ${spnTenantId} -spnAuthority ${spnAuthority} -subscriptionId ${subscription().subscriptionId} -resourceGroup ${resourceGroup().name} -azureLocation ${location} -stagingStorageAccountName ${storageAccountName} -workspaceName ${workspaceName} -templateBaseUrl ${templateBaseUrl} -acrName ${acrName} -rdpPort ${rdpPort} -githubAccount ${githubAccount} -githubBranch ${githubBranch} -namingGuid ${namingGuid} -adxClusterName ${adxClusterName} -customLocationRPOID ${customLocationRPOID} -scenario ${scenario} -aioStorageAccountName ${aioStorageAccountName} -vmAutologon ${vmAutologon}' } } } diff --git a/azure_jumpstart_ag/manufacturing/bicep/data/dataExplorer.bicep b/azure_jumpstart_ag/contoso_motors/bicep/data/dataExplorer.bicep similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/data/dataExplorer.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/data/dataExplorer.bicep diff --git a/azure_jumpstart_ag/manufacturing/bicep/data/eventGrid.bicep b/azure_jumpstart_ag/contoso_motors/bicep/data/eventGrid.bicep similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/data/eventGrid.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/data/eventGrid.bicep diff --git a/azure_jumpstart_ag/manufacturing/bicep/data/eventHub.bicep b/azure_jumpstart_ag/contoso_motors/bicep/data/eventHub.bicep similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/data/eventHub.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/data/eventHub.bicep diff --git a/azure_jumpstart_ag/manufacturing/bicep/data/keyVault.bicep b/azure_jumpstart_ag/contoso_motors/bicep/data/keyVault.bicep similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/data/keyVault.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/data/keyVault.bicep diff --git a/azure_jumpstart_ag/manufacturing/bicep/data/script.kql b/azure_jumpstart_ag/contoso_motors/bicep/data/script.kql similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/data/script.kql rename to azure_jumpstart_ag/contoso_motors/bicep/data/script.kql diff --git a/azure_jumpstart_ag/manufacturing/bicep/kubernetes/acr.bicep b/azure_jumpstart_ag/contoso_motors/bicep/kubernetes/acr.bicep similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/kubernetes/acr.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/kubernetes/acr.bicep diff --git a/azure_jumpstart_ag/manufacturing/bicep/main.azd.bicep b/azure_jumpstart_ag/contoso_motors/bicep/main.azd.bicep similarity index 95% rename from azure_jumpstart_ag/manufacturing/bicep/main.azd.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/main.azd.bicep index f751cc8409..e4234c81d5 100644 --- a/azure_jumpstart_ag/manufacturing/bicep/main.azd.bicep +++ b/azure_jumpstart_ag/contoso_motors/bicep/main.azd.bicep @@ -81,9 +81,6 @@ param akvNameSite2 string = 'agakv2${namingGuid}' @description('Name of the storage account') param aioStorageAccountName string = 'aiostg${namingGuid}' -@description('The name of ESA container in Storage Account') -param stcontainerName string = 'esacontainer' - @description('The name of the Azure Data Explorer cluster') param adxClusterName string = 'agadx${namingGuid}' @@ -98,8 +95,8 @@ param acrName string = 'agacr${namingGuid}' @description('Override default RDP port using this parameter. Default is 3389. No changes will be made to the client VM.') param rdpPort string = '3389' -@description('The agora industry to be deployed') -param industry string = 'manufacturing' +@description('The agora scenario to be deployed') +param scenario string = 'contoso_motors' var templateBaseUrl = 'https://raw.githubusercontent.com/${githubAccount}/azure_arc/${githubBranch}/azure_jumpstart_ag/' @@ -156,8 +153,7 @@ module clientVmDeployment 'clientVm/clientVm.bicep' = { namingGuid: namingGuid adxClusterName: adxClusterName customLocationRPOID: customLocationRPOID - industry: industry - stcontainerName: stcontainerName + scenario: scenario } } @@ -178,7 +174,6 @@ module storageAccount 'storage/storageAccount.bicep' = { storageAccountName: aioStorageAccountName location: location storageQueueName: storageQueueName - stcontainerName: stcontainerName } } diff --git a/azure_jumpstart_ag/manufacturing/bicep/main.azd.parameters.json b/azure_jumpstart_ag/contoso_motors/bicep/main.azd.parameters.json similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/main.azd.parameters.json rename to azure_jumpstart_ag/contoso_motors/bicep/main.azd.parameters.json diff --git a/azure_jumpstart_ag/manufacturing/bicep/main.bicep b/azure_jumpstart_ag/contoso_motors/bicep/main.bicep similarity index 90% rename from azure_jumpstart_ag/manufacturing/bicep/main.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/main.bicep index 15dbbc0d8e..a2932d6149 100644 --- a/azure_jumpstart_ag/manufacturing/bicep/main.bicep +++ b/azure_jumpstart_ag/contoso_motors/bicep/main.bicep @@ -72,9 +72,6 @@ param stagingDataCGName string = 'mqttdataemulator' @description('Name of the storage account') param aioStorageAccountName string = 'aiostg${namingGuid}' -@description('The name of ESA container in Storage Account') -param stcontainerName string = 'esacontainer' - @description('The name of the Azure Data Explorer cluster') param adxClusterName string = 'agadx${namingGuid}' @@ -89,13 +86,11 @@ param acrName string = 'agacr${namingGuid}' @description('Override default RDP port using this parameter. Default is 3389. No changes will be made to the client VM.') param rdpPort string = '3389' -@description('The agora industry to be deployed') -param industry string = 'manufacturing' +@description('Enable automatic logon into Virtual Machine') +param vmAutologon bool = true -@description('''The AKS Edge Essentials schema version to be used. This is only used to pin the AKS Edge Essentials schema version for testing. -To pin a specific version, use the format '1.14'. To use the latest schema version, use 'useLatest'. -''') -param AKSEEPinnedSchemaVersion string = '1.14' +@description('The agora scenario to be deployed') +param scenario string = 'contoso_motors' var templateBaseUrl = 'https://raw.githubusercontent.com/${githubAccount}/azure_arc/${githubBranch}/azure_jumpstart_ag/' @@ -148,10 +143,9 @@ module clientVmDeployment 'clientVm/clientVm.bicep' = { namingGuid: namingGuid adxClusterName: adxClusterName customLocationRPOID: customLocationRPOID - industry: industry + scenario: scenario aioStorageAccountName: aioStorageAccountName - stcontainerName: stcontainerName - AKSEEPinnedSchemaVersion: AKSEEPinnedSchemaVersion + vmAutologon: vmAutologon } } @@ -171,7 +165,6 @@ module storageAccount 'storage/storageAccount.bicep' = { storageAccountName: aioStorageAccountName location: location storageQueueName: storageQueueName - stcontainerName: stcontainerName } } diff --git a/azure_jumpstart_ag/manufacturing/bicep/main.parameters.json b/azure_jumpstart_ag/contoso_motors/bicep/main.parameters.json similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/main.parameters.json rename to azure_jumpstart_ag/contoso_motors/bicep/main.parameters.json diff --git a/azure_jumpstart_ag/manufacturing/bicep/mgmt/VMInsightsDCR.bicep b/azure_jumpstart_ag/contoso_motors/bicep/mgmt/VMInsightsDCR.bicep similarity index 97% rename from azure_jumpstart_ag/manufacturing/bicep/mgmt/VMInsightsDCR.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/mgmt/VMInsightsDCR.bicep index 6e904cec50..0711c46551 100644 --- a/azure_jumpstart_ag/manufacturing/bicep/mgmt/VMInsightsDCR.bicep +++ b/azure_jumpstart_ag/contoso_motors/bicep/mgmt/VMInsightsDCR.bicep @@ -18,7 +18,6 @@ resource MSVMI_PerfandDa_Dcr 'Microsoft.Insights/dataCollectionRules@2021-04-01' { name: 'VMInsightsPerfCounters' streams: ['Microsoft-InsightsMetrics'] - scheduledTransferPeriod: 'PT1M' samplingFrequencyInSeconds: 60 counterSpecifiers: ['\\VmInsights\\DetailedMetrics'] } diff --git a/azure_jumpstart_ag/manufacturing/bicep/mgmt/mgmtArtifacts.bicep b/azure_jumpstart_ag/contoso_motors/bicep/mgmt/mgmtArtifacts.bicep similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/mgmt/mgmtArtifacts.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/mgmt/mgmtArtifacts.bicep diff --git a/azure_jumpstart_ag/manufacturing/bicep/mgmt/network.bicep b/azure_jumpstart_ag/contoso_motors/bicep/mgmt/network.bicep similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/mgmt/network.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/mgmt/network.bicep diff --git a/azure_jumpstart_ag/manufacturing/bicep/mgmt/policyAzureArcRGScope.bicep b/azure_jumpstart_ag/contoso_motors/bicep/mgmt/policyAzureArcRGScope.bicep similarity index 91% rename from azure_jumpstart_ag/manufacturing/bicep/mgmt/policyAzureArcRGScope.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/mgmt/policyAzureArcRGScope.bicep index 7f550c7418..3efbd87c55 100644 --- a/azure_jumpstart_ag/manufacturing/bicep/mgmt/policyAzureArcRGScope.bicep +++ b/azure_jumpstart_ag/contoso_motors/bicep/mgmt/policyAzureArcRGScope.bicep @@ -56,7 +56,7 @@ resource policies_name 'Microsoft.Authorization/policyAssignments@2022-06-01' = type: 'SystemAssigned' } properties: { - policyDefinitionId: item.definitionId + policyDefinitionId: any(item.definitionId) parameters: item.parameters } }] @@ -64,7 +64,7 @@ resource policies_name 'Microsoft.Authorization/policyAssignments@2022-06-01' = resource policy_AMA_role_0 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid( policies[0].name, policies[0].roleDefinition[0],resourceGroup().id) properties: { - roleDefinitionId: policies[0].roleDefinition[0] + roleDefinitionId: any(policies[0].roleDefinition[0]) principalId: policies_name[0].identity.principalId principalType: 'ServicePrincipal' } @@ -73,7 +73,7 @@ resource policy_AMA_role_0 'Microsoft.Authorization/roleAssignments@2022-04-01' resource policy_AMA_role_1 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid( policies[0].name, policies[0].roleDefinition[1],resourceGroup().id) properties: { - roleDefinitionId: policies[0].roleDefinition[1] + roleDefinitionId: any(policies[0].roleDefinition[1]) principalId: policies_name[0].identity.principalId principalType: 'ServicePrincipal' } @@ -82,7 +82,7 @@ resource policy_AMA_role_1 'Microsoft.Authorization/roleAssignments@2022-04-01' resource policy_AMA_role_2 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid( policies[0].name, policies[0].roleDefinition[2],resourceGroup().id) properties: { - roleDefinitionId: policies[0].roleDefinition[2] + roleDefinitionId: any(policies[0].roleDefinition[2]) principalId: policies_name[0].identity.principalId principalType: 'ServicePrincipal' } @@ -91,7 +91,7 @@ resource policy_AMA_role_2 'Microsoft.Authorization/roleAssignments@2022-04-01' resource policy_arc_windows_azure_security_agent 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid( policies[1].name, policies[1].roleDefinition,resourceGroup().id) properties: { - roleDefinitionId: policies[1].roleDefinition + roleDefinitionId: any(policies[1].roleDefinition) principalId: policies_name[1].identity.principalId principalType: 'ServicePrincipal' } @@ -100,7 +100,7 @@ resource policy_arc_windows_azure_security_agent 'Microsoft.Authorization/roleAs resource policy_arc_linux_azure_security_agent 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid( policies[2].name, policies[2].roleDefinition,resourceGroup().id) properties: { - roleDefinitionId: policies[2].roleDefinition + roleDefinitionId: any(policies[2].roleDefinition) principalId: policies_name[2].identity.principalId principalType: 'ServicePrincipal' } @@ -109,7 +109,7 @@ resource policy_arc_linux_azure_security_agent 'Microsoft.Authorization/roleAssi resource policy_arc_windows_mde 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid( policies[3].name, policies[3].roleDefinition,resourceGroup().id) properties: { - roleDefinitionId: policies[3].roleDefinition + roleDefinitionId: any(policies[3].roleDefinition) principalId: policies_name[3].identity.principalId principalType: 'ServicePrincipal' } @@ -118,7 +118,7 @@ resource policy_arc_windows_mde 'Microsoft.Authorization/roleAssignments@2022-04 resource policy_arc_linux_mde 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid( policies[4].name, policies[4].roleDefinition,resourceGroup().id) properties: { - roleDefinitionId: policies[4].roleDefinition + roleDefinitionId: any(policies[4].roleDefinition) principalId: policies_name[4].identity.principalId principalType: 'ServicePrincipal' } diff --git a/azure_jumpstart_ag/manufacturing/bicep/mgmt/storageAccount.bicep b/azure_jumpstart_ag/contoso_motors/bicep/mgmt/storageAccount.bicep similarity index 100% rename from azure_jumpstart_ag/manufacturing/bicep/mgmt/storageAccount.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/mgmt/storageAccount.bicep diff --git a/azure_jumpstart_ag/manufacturing/bicep/storage/storageAccount.bicep b/azure_jumpstart_ag/contoso_motors/bicep/storage/storageAccount.bicep similarity index 75% rename from azure_jumpstart_ag/manufacturing/bicep/storage/storageAccount.bicep rename to azure_jumpstart_ag/contoso_motors/bicep/storage/storageAccount.bicep index 35d095bce9..baa298048b 100644 --- a/azure_jumpstart_ag/manufacturing/bicep/storage/storageAccount.bicep +++ b/azure_jumpstart_ag/contoso_motors/bicep/storage/storageAccount.bicep @@ -12,9 +12,6 @@ param skuName string = 'Standard_LRS' param storageQueueName string = 'aioQueue' -@description('The name of ESA container in Storage Account') -param stcontainerName string - resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: storageAccountName location: location @@ -37,12 +34,5 @@ resource storageQueue 'Microsoft.Storage/storageAccounts/queueServices/queues@20 name: storageQueueName } -resource storageAccountName_default_container 'Microsoft.Storage/storageAccounts/blobServices/containers@2021-04-01' = { - name: '${storageAccountName}/default/${stcontainerName}' - dependsOn: [ - storageAccount - ] -} - output queueName string = storageQueueName output storageAccountId string = storageAccount.id diff --git a/azure_jumpstart_ag/manufacturing/scripts/postprovision.ps1 b/azure_jumpstart_ag/contoso_motors/scripts/postprovision.ps1 similarity index 100% rename from azure_jumpstart_ag/manufacturing/scripts/postprovision.ps1 rename to azure_jumpstart_ag/contoso_motors/scripts/postprovision.ps1 diff --git a/azure_jumpstart_ag/manufacturing/scripts/predown.ps1 b/azure_jumpstart_ag/contoso_motors/scripts/predown.ps1 similarity index 100% rename from azure_jumpstart_ag/manufacturing/scripts/predown.ps1 rename to azure_jumpstart_ag/contoso_motors/scripts/predown.ps1 diff --git a/azure_jumpstart_ag/manufacturing/scripts/preprovision.ps1 b/azure_jumpstart_ag/contoso_motors/scripts/preprovision.ps1 similarity index 100% rename from azure_jumpstart_ag/manufacturing/scripts/preprovision.ps1 rename to azure_jumpstart_ag/contoso_motors/scripts/preprovision.ps1 diff --git a/azure_jumpstart_ag/contoso_supermarket/.gitignore b/azure_jumpstart_ag/contoso_supermarket/.gitignore new file mode 100644 index 0000000000..6297a3b672 --- /dev/null +++ b/azure_jumpstart_ag/contoso_supermarket/.gitignore @@ -0,0 +1,2 @@ +.azure +js_rsa* \ No newline at end of file diff --git a/azure_jumpstart_ag/contoso_supermarket/azure.yaml b/azure_jumpstart_ag/contoso_supermarket/azure.yaml new file mode 100644 index 0000000000..200ea17596 --- /dev/null +++ b/azure_jumpstart_ag/contoso_supermarket/azure.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json + +name: azure_jumpstart_ag +metadata: + template: azure_jumpstart_agora@0.0.1-beta +infra: + provider: "bicep" + path: "bicep" + module: "main.azd" +hooks: + preprovision: + shell: pwsh + run: ./scripts/preprovision.ps1 + continueOnError: false + interactive: true + postprovision: + shell: pwsh + run: ./scripts/postprovision.ps1 + continueOnError: false + interactive: true \ No newline at end of file diff --git a/azure_jumpstart_ag/retail/bicep/clientVm/clientVm.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/clientVm/clientVm.bicep similarity index 91% rename from azure_jumpstart_ag/retail/bicep/clientVm/clientVm.bicep rename to azure_jumpstart_ag/contoso_supermarket/bicep/clientVm/clientVm.bicep index a7bf32626b..9bf77ee67a 100644 --- a/azure_jumpstart_ag/retail/bicep/clientVm/clientVm.bicep +++ b/azure_jumpstart_ag/contoso_supermarket/bicep/clientVm/clientVm.bicep @@ -16,6 +16,9 @@ param windowsOSVersion string = '2022-datacenter-g2' @description('Location for all resources') param location string = resourceGroup().location +@description('Enable automatic logon into Virtual Machine') +param vmAutologon bool = false + @description('Resource tag for Jumpstart Agora') param resourceTags object = { Project: 'Jumpstart_Agora' @@ -84,11 +87,8 @@ param adxClusterName string @description('Random GUID') param namingGuid string -@description('The agora industry to be deployed') -param industry string = 'retail' - -@description('The AKS Edge Essentials schema version to be used. This is only used to pin the AKS Edge Essentials schema version for testing.') -param AKSEEPinnedSchemaVersion string = 'useLatest' +@description('The agora scenario to be deployed') +param scenario string = 'conotos_supermarket' var encodedPassword = base64(windowsAdminPassword) var bastionName = 'Ag-Bastion' @@ -182,7 +182,15 @@ resource vm 'Microsoft.Compute/virtualMachines@2022-11-01' = { adminPassword: windowsAdminPassword windowsConfiguration: { provisionVMAgent: true - enableAutomaticUpdates: false + enableAutomaticUpdates: true + enableVMAgentPlatformUpdates: true + patchSettings: { + assessmentMode: 'AutomaticByPlatform' + patchMode: 'AutomaticByPlatform' + automaticByPlatformSettings: { + rebootSetting: 'Never' + } + } } } } @@ -204,7 +212,7 @@ resource vmBootstrap 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = fileUris: [ uri(templateBaseUrl, 'artifacts/PowerShell/Bootstrap.ps1') ] - commandToExecute: 'powershell.exe -ExecutionPolicy Bypass -File Bootstrap.ps1 -adminUsername ${windowsAdminUsername} -adminPassword ${encodedPassword} -spnClientId ${spnClientId} -spnClientSecret ${spnClientSecret} -spnTenantId ${spnTenantId} -spnAuthority ${spnAuthority} -subscriptionId ${subscription().subscriptionId} -resourceGroup ${resourceGroup().name} -azureLocation ${location} -stagingStorageAccountName ${storageAccountName} -workspaceName ${workspaceName} -templateBaseUrl ${templateBaseUrl} -githubUser ${githubUser} -aksStagingClusterName ${aksStagingClusterName} -iotHubHostName ${iotHubHostName} -acrName ${acrName} -cosmosDBName ${cosmosDBName} -cosmosDBEndpoint ${cosmosDBEndpoint} -rdpPort ${rdpPort} -githubAccount ${githubAccount} -githubBranch ${githubBranch} -githubPAT ${githubPAT} -adxClusterName ${adxClusterName} -namingGuid ${namingGuid} -industry ${industry} -AKSEEPinnedSchemaVersion ${AKSEEPinnedSchemaVersion}' + commandToExecute: 'powershell.exe -ExecutionPolicy Bypass -File Bootstrap.ps1 -adminUsername ${windowsAdminUsername} -adminPassword ${encodedPassword} -spnClientId ${spnClientId} -spnClientSecret ${spnClientSecret} -spnTenantId ${spnTenantId} -spnAuthority ${spnAuthority} -subscriptionId ${subscription().subscriptionId} -resourceGroup ${resourceGroup().name} -azureLocation ${location} -stagingStorageAccountName ${storageAccountName} -workspaceName ${workspaceName} -templateBaseUrl ${templateBaseUrl} -githubUser ${githubUser} -aksStagingClusterName ${aksStagingClusterName} -iotHubHostName ${iotHubHostName} -acrName ${acrName} -cosmosDBName ${cosmosDBName} -cosmosDBEndpoint ${cosmosDBEndpoint} -rdpPort ${rdpPort} -githubAccount ${githubAccount} -githubBranch ${githubBranch} -githubPAT ${githubPAT} -adxClusterName ${adxClusterName} -namingGuid ${namingGuid} -scenario ${scenario} -vmAutologon ${vmAutologon}' } } } diff --git a/azure_jumpstart_ag/retail/bicep/data/cosmosDB.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/data/cosmosDB.bicep similarity index 100% rename from azure_jumpstart_ag/retail/bicep/data/cosmosDB.bicep rename to azure_jumpstart_ag/contoso_supermarket/bicep/data/cosmosDB.bicep diff --git a/azure_jumpstart_ag/retail/bicep/data/dataExplorer.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/data/dataExplorer.bicep similarity index 100% rename from azure_jumpstart_ag/retail/bicep/data/dataExplorer.bicep rename to azure_jumpstart_ag/contoso_supermarket/bicep/data/dataExplorer.bicep diff --git a/azure_jumpstart_ag/retail/bicep/data/iotHub.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/data/iotHub.bicep similarity index 100% rename from azure_jumpstart_ag/retail/bicep/data/iotHub.bicep rename to azure_jumpstart_ag/contoso_supermarket/bicep/data/iotHub.bicep diff --git a/azure_jumpstart_ag/retail/bicep/data/script.kql b/azure_jumpstart_ag/contoso_supermarket/bicep/data/script.kql similarity index 100% rename from azure_jumpstart_ag/retail/bicep/data/script.kql rename to azure_jumpstart_ag/contoso_supermarket/bicep/data/script.kql diff --git a/azure_jumpstart_ag/retail/bicep/kubernetes/aks.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/kubernetes/aks.bicep similarity index 96% rename from azure_jumpstart_ag/retail/bicep/kubernetes/aks.bicep rename to azure_jumpstart_ag/contoso_supermarket/bicep/kubernetes/aks.bicep index 024b0e4599..e54098af6c 100644 --- a/azure_jumpstart_ag/retail/bicep/kubernetes/aks.bicep +++ b/azure_jumpstart_ag/contoso_supermarket/bicep/kubernetes/aks.bicep @@ -67,7 +67,7 @@ param kubernetesVersion string = '1.28.5' var serviceCidr_staging = '10.21.64.0/19' var dnsServiceIP_staging = '10.21.64.10' -resource aksStaging 'Microsoft.ContainerService/managedClusters@2024-04-02-preview' = { +resource aksStaging 'Microsoft.ContainerService/managedClusters@2023-05-02-preview' = { location: location name: aksStagingClusterName tags: resourceTags @@ -102,10 +102,6 @@ resource aksStaging 'Microsoft.ContainerService/managedClusters@2024-04-02-previ enabled: true } } - autoUpgradeProfile: { - upgradeChannel: 'stable' - nodeOSUpgradeChannel: 'NodeImage' - } networkProfile: { networkPlugin: 'azure' serviceCidr: serviceCidr_staging diff --git a/azure_jumpstart_ag/retail/bicep/main.azd.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/main.azd.bicep similarity index 98% rename from azure_jumpstart_ag/retail/bicep/main.azd.bicep rename to azure_jumpstart_ag/contoso_supermarket/bicep/main.azd.bicep index cb6680b118..6c8e6ee20b 100644 --- a/azure_jumpstart_ag/retail/bicep/main.azd.bicep +++ b/azure_jumpstart_ag/contoso_supermarket/bicep/main.azd.bicep @@ -87,8 +87,8 @@ param acrName string = 'agacr${namingGuid}' @description('Override default RDP port using this parameter. Default is 3389. No changes will be made to the client VM.') param rdpPort string = '3389' -@description('The agora industry to be deployed') -param industry string = 'retail' +@description('The agora scenario to be deployed') +param scenario string = 'contoso_supermarket' var templateBaseUrl = 'https://raw.githubusercontent.com/${githubAccount}/azure_arc/${githubBranch}/azure_jumpstart_ag/' @@ -170,7 +170,7 @@ module clientVmDeployment 'clientVm/clientVm.bicep' = { rdpPort: rdpPort adxClusterName: adxClusterName namingGuid: namingGuid - industry: industry + scenario: scenario } } diff --git a/azure_jumpstart_ag/retail/bicep/main.azd.parameters.json b/azure_jumpstart_ag/contoso_supermarket/bicep/main.azd.parameters.json similarity index 100% rename from azure_jumpstart_ag/retail/bicep/main.azd.parameters.json rename to azure_jumpstart_ag/contoso_supermarket/bicep/main.azd.parameters.json diff --git a/azure_jumpstart_ag/retail/bicep/main.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/main.bicep similarity index 92% rename from azure_jumpstart_ag/retail/bicep/main.bicep rename to azure_jumpstart_ag/contoso_supermarket/bicep/main.bicep index 221afa3b74..268003a7c8 100644 --- a/azure_jumpstart_ag/retail/bicep/main.bicep +++ b/azure_jumpstart_ag/contoso_supermarket/bicep/main.bicep @@ -80,13 +80,11 @@ param acrName string = 'agacr${namingGuid}' @description('Override default RDP port using this parameter. Default is 3389. No changes will be made to the client VM.') param rdpPort string = '3389' -@description('The agora industry to be deployed') -param industry string = 'retail' +@description('Enable automatic logon into Virtual Machine') +param vmAutologon bool = true -@description('''The AKS Edge Essentials schema version to be used. This is only used to pin the AKS Edge Essentials schema version for testing. -To pin a specific version, use the format '1.14'. To use the latest schema version, use 'useLatest'. -''') -param AKSEEPinnedSchemaVersion string = '1.14' +@description('The agora scenario to be deployed') +param scenario string = 'contoso_supermarket' var templateBaseUrl = 'https://raw.githubusercontent.com/${githubAccount}/azure_arc/${githubBranch}/azure_jumpstart_ag/' @@ -156,8 +154,8 @@ module clientVmDeployment 'clientVm/clientVm.bicep' = { rdpPort: rdpPort adxClusterName: adxClusterName namingGuid: namingGuid - industry: industry - AKSEEPinnedSchemaVersion: AKSEEPinnedSchemaVersion + scenario: scenario + vmAutologon: vmAutologon } } diff --git a/azure_jumpstart_ag/retail/bicep/main.parameters.json b/azure_jumpstart_ag/contoso_supermarket/bicep/main.parameters.json similarity index 100% rename from azure_jumpstart_ag/retail/bicep/main.parameters.json rename to azure_jumpstart_ag/contoso_supermarket/bicep/main.parameters.json diff --git a/azure_jumpstart_ag/contoso_supermarket/bicep/mgmt/mgmtArtifacts.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/mgmt/mgmtArtifacts.bicep new file mode 100644 index 0000000000..ec7b5ea53b --- /dev/null +++ b/azure_jumpstart_ag/contoso_supermarket/bicep/mgmt/mgmtArtifacts.bicep @@ -0,0 +1,52 @@ +@description('Name for your log analytics workspace') +param workspaceName string + +@description('Azure Region to deploy the Log Analytics Workspace') +param location string = resourceGroup().location + +@description('Resource tag for Jumpstart Agora') +param resourceTags object = { + Project: 'Jumpstart_Agora' +} + +@description('SKU, leave default pergb2018') +param sku string = 'pergb2018' + +var security = { + name: 'Security(${workspaceName})' + galleryName: 'Security' +} + +resource workspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { + name: workspaceName + location: location + tags: resourceTags + properties: { + sku: { + name: sku + } + } +} + +resource securityGallery 'Microsoft.OperationsManagement/solutions@2015-11-01-preview' = { + name: security.name + location: location + tags: resourceTags + properties: { + workspaceResourceId: workspace.id + } + plan: { + name: security.name + promotionCode: '' + product: 'OMSGallery/${security.galleryName}' + publisher: 'Microsoft' + } +} + +module policyDeploymentRGScope './policyAzureArcRGScope.bicep' = { + name: 'policyDeployment' + params: { + azureLocation: location + logAnalyticsWorkspaceId: workspace.id + } +} diff --git a/azure_jumpstart_ag/retail/bicep/mgmt/network.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/mgmt/network.bicep similarity index 100% rename from azure_jumpstart_ag/retail/bicep/mgmt/network.bicep rename to azure_jumpstart_ag/contoso_supermarket/bicep/mgmt/network.bicep diff --git a/azure_jumpstart_ag/retail/bicep/mgmt/policyAzureArcRGScope.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/mgmt/policyAzureArcRGScope.bicep similarity index 100% rename from azure_jumpstart_ag/retail/bicep/mgmt/policyAzureArcRGScope.bicep rename to azure_jumpstart_ag/contoso_supermarket/bicep/mgmt/policyAzureArcRGScope.bicep diff --git a/azure_jumpstart_ag/retail/bicep/mgmt/storageAccount.bicep b/azure_jumpstart_ag/contoso_supermarket/bicep/mgmt/storageAccount.bicep similarity index 100% rename from azure_jumpstart_ag/retail/bicep/mgmt/storageAccount.bicep rename to azure_jumpstart_ag/contoso_supermarket/bicep/mgmt/storageAccount.bicep diff --git a/azure_jumpstart_ag/contoso_supermarket/scripts/postprovision.ps1 b/azure_jumpstart_ag/contoso_supermarket/scripts/postprovision.ps1 new file mode 100644 index 0000000000..1105069670 --- /dev/null +++ b/azure_jumpstart_ag/contoso_supermarket/scripts/postprovision.ps1 @@ -0,0 +1,84 @@ +if ($null -ne $env:AZURE_RESOURCE_GROUP){ + $resourceGroup = $env:AZURE_RESOURCE_GROUP + $adxClusterName = $env:ADX_CLUSTER_NAME + Select-AzSubscription -SubscriptionId $env:AZURE_SUBSCRIPTION_ID | out-null + $rdpPort = $env:JS_RDP_PORT +} else { + # This section is for testing only + $resourceGroup = "charris-js-ag-43-rg" + $adxClusterName = "agadx2827a" + Get-AzSubscription -SubscriptionName "Azure Arc Jumpstart Subscription" | Select-AzSubscription +} + +######################################################################## +# ADX Dashboards +######################################################################## + +Write-Host "Importing Azure Data Explorer dashboards..." + +# Get the ADX/Kusto cluster info +$kustoCluster = Get-AzKustoCluster -ResourceGroupName $resourceGroup -Name $adxClusterName +$adxEndPoint = $kustoCluster.Uri + +# Update the dashboards files with the new ADX cluster name and URI +$templateBaseUrl = "https://raw.githubusercontent.com/microsoft/azure_arc/main/azure_jumpstart_ag/contoso_supermarket/" +$ordersDashboardBody = (Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/adx_dashboards/adx-dashboard-orders-payload.json").Content -replace '{{ADX_CLUSTER_URI}}', $adxEndPoint -replace '{{ADX_CLUSTER_NAME}}', $adxClusterName +$iotSensorsDashboardBody = (Invoke-WebRequest -Method Get -Uri "$templateBaseUrl/artifacts/adx_dashboards/adx-dashboard-iotsensor-payload.json") -replace '{{ADX_CLUSTER_URI}}', $adxEndPoint -replace '{{ADX_CLUSTER_NAME}}', $adxClusterName + +# Get access token to make REST API call to Azure Data Explorer Dashabord API. Replace double quotes surrounding access token +$token = (az account get-access-token --scope "https://rtd-metadata.azurewebsites.net/user_impersonation openid profile offline_access" --query "accessToken") -replace "`"", "" + +# Prepare authorization header with access token +$httpHeaders = @{"Authorization" = "Bearer $token"; "Content-Type" = "application/json" } + +# Make REST API call to the dashboard endpoint. +$dashboardApi = "https://dashboards.kusto.windows.net/dashboards" + +# Import orders dashboard report +$httpResponse = Invoke-WebRequest -Method Post -Uri $dashboardApi -Body $ordersDashboardBody -Headers $httpHeaders +if ($httpResponse.StatusCode -ne 200){ + Write-Host "ERROR: Failed import orders dashboard report into Azure Data Explorer" -ForegroundColor Red +} + +# Import IoT Sensor dashboard report +$httpResponse = Invoke-WebRequest -Method Post -Uri $dashboardApi -Body $iotSensorsDashboardBody -Headers $httpHeaders +if ($httpResponse.StatusCode -ne 200){ + Write-Host "ERROR: Failed import IoT Sensor dashboard report into Azure Data Explorer" -ForegroundColor Red +} + + +######################################################################## +# RDP Port +######################################################################## + +# Configure NSG Rule for RDP (if needed) +If ($rdpPort -ne "3389") { + + Write-Host "Configuring NSG Rule for RDP..." + $nsg = Get-AzNetworkSecurityGroup -ResourceGroupName $resourceGroup -Name Ag-NSG-Prod + + Add-AzNetworkSecurityRuleConfig ` + -NetworkSecurityGroup $nsg ` + -Name "RDP-$rdpPort" ` + -Description "Allow RDP" ` + -Access Allow ` + -Protocol Tcp ` + -Direction Inbound ` + -Priority 100 ` + -SourceAddressPrefix * ` + -SourcePortRange * ` + -DestinationAddressPrefix * ` + -DestinationPortRange $rdpPort ` + | Out-Null + + Set-AzNetworkSecurityGroup -NetworkSecurityGroup $nsg | Out-Null + # az network nsg rule create -g $resourceGroup --nsg-name Ag-NSG-Prod --name "RDC-$rdpPort" --priority 100 --source-address-prefixes * --destination-port-ranges $rdpPort --access Allow --protocol Tcp +} + + +# Client VM IP address +$ip = (Get-AzPublicIpAddress -ResourceGroupName $resourceGroup -Name "Ag-VM-Client-PIP").IpAddress + +Write-Host "You can now connect to the client VM using the following command: " -NoNewline +WRite-Host "mstsc /v:$($ip):$($rdpPort)" -ForegroundColor Green -BackgroundColor Black +Write-Host "Remember to use the Windows admin user name [$env:JS_WINDOWS_ADMIN_USERNAME] and the password you specified." diff --git a/azure_jumpstart_ag/contoso_supermarket/scripts/preprovision.ps1 b/azure_jumpstart_ag/contoso_supermarket/scripts/preprovision.ps1 new file mode 100644 index 0000000000..7d1be08c4b --- /dev/null +++ b/azure_jumpstart_ag/contoso_supermarket/scripts/preprovision.ps1 @@ -0,0 +1,248 @@ +######################################################################## +# Connect to Azure +######################################################################## + +Write-Host "Connecting to Azure..." + +# Install Azure module if not already installed +if (-not (Get-Command -Name Get-AzContext)) { + Write-Host "Installing Azure module..." + Install-Module -Name Az -AllowClobber -Scope CurrentUser -ErrorAction Stop +} + +# If not signed in, run the Connect-AzAccount cmdlet +if (-not (Get-AzContext)) { + Write-Host "Logging in to Azure..." + If (-not (Connect-AzAccount -SubscriptionId $env:AZURE_SUBSCRIPTION_ID -ErrorAction Stop)){ + Throw "Unable to login to Azure. Please check your credentials and try again." + } +} + +# Write-Host "Getting Azure Tenant Id..." +$tenantId = (Get-AzSubscription -SubscriptionId $env:AZURE_SUBSCRIPTION_ID).TenantId + +# Write-Host "Setting Azure context..." +$context = Set-AzContext -SubscriptionId $env:AZURE_SUBSCRIPTION_ID -Tenant $tenantId -ErrorAction Stop + +# Write-Host "Setting az subscription..." +$azLogin = az account set --subscription $env:AZURE_SUBSCRIPTION_ID + + +######################################################################## +# Check for available capacity in region +######################################################################## +#region Functions +Function Get-AzAvailableCores ($location, $skuFriendlyNames, $minCores = 0) { + # using az command because there is currently a bug in various versions of PowerShell that affects Get-AzVMUsage + $usage = (az vm list-usage --location $location --output json --only-show-errors) | ConvertFrom-Json + + $usage = $usage | + Where-Object {$_.localname -match $skuFriendlyNames} + + $enhanced = $usage | + ForEach-Object { + $_ | Add-Member -MemberType NoteProperty -Name available -Value 0 -Force -PassThru + $_.available = $_.limit - $_.currentValue + } + + $enhanced = $enhanced | + ForEach-Object { + $_ | Add-Member -MemberType NoteProperty -Name usableLocation -Value $false -Force -PassThru + If ($_.available -ge $minCores) { + $_.usableLocation = $true + } + else { + $_.usableLocation = $false + } + } + + $enhanced + +} + +Function Get-AzAvailableLocations ($location, $skuFriendlyNames, $minCores = 0) { + $allLocations = get-AzLocation + $geographyGroup = ($allLocations | Where-Object {$_.location -eq $location}).GeographyGroup + $locations = $allLocations | Where-Object { ` + $_.GeographyGroup -eq $geographyGroup ` + -and $_.Location -ne $location ` + -and $_.RegionCategory -eq "Recommended" ` + -and $_.PhysicalLocation -ne "" + } + + $usableLocations = $locations | + ForEach-Object { + $available = Get-AzAvailableCores -location $_.location -skuFriendlyNames $skuFriendlyNames -minCores $minCores | + Where-Object {$_.localName -ne "Total Regional vCPUs"} + If ($available.usableLocation) { + $_ | Add-Member -MemberType NoteProperty -Name TotalCores -Value $available.limit -Force + $_ | Add-Member -MemberType NoteProperty -Name AvailableCores -Value $available.available -Force + $_ | Add-Member -MemberType NoteProperty -Name usableLocation -Value $available.usableLocation -Force -PassThru + } + } + + $usableLocations +} + +Function Get-AzAvailablePublicIpAddress ($location, $subscriptionId, $minPublicIP = 0) { + + $accessToken = az account get-access-token --query accessToken -o tsv + $headers = @{ + "Authorization" = "Bearer $accessToken" + } + + $uri = "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/locations/$location/usages?api-version=2023-02-01" + + $publicIpCount = (Get-AzPublicIpAddress | where-object {$_.location -eq $location} | measure-object).count + $response = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get + + $limit = ($response.value | where-object { $_.name.value -eq "PublicIPAddresses"}).limit + + $availableIP = $limit - $publicIpCount + + $availableIP + +} + +#endregion Functions + +$location = $env:AZURE_LOCATION +$subscriptionId = $env:AZURE_SUBSCRIPTION_ID +$minCores = 32 +$minPublicIP = 10 +$skuFriendlyNames = "Standard DSv5 Family vCPUs|Total Regional vCPUs" + +Write-Host "`nChecking for available capacity in $location region..." + +$available = Get-AzAvailableCores -location $location -skuFriendlyNames $skuFriendlyNames -minCores $minCores + +If ($available.usableLocation -contains $false) { + Write-Host "`n`u{274C} There is not enough VM capacity in the $location region to deploy the Jumpstart environment." -ForegroundColor Red + + Write-Host "`nChecking other regions in the same geography with enough capacity ($minCores cores)...`n" + + $locations = Get-AzAvailableLocations -location $location -skuFriendlyNames $skuFriendlyNames -minCores $minCores | + Format-Table Location, DisplayName, TotalCores, AvailableCores, UsableLocation -AutoSize | Out-String + + Write-Host $locations + + Write-Host "Please run ``azd env --new`` to create a new environment and select the new location.`n" + + $message = "Not enough capacity in $location region." + Throw $message + +} else { + $availableIP = Get-AzAvailablePublicIpAddress -location $location -subscriptionId $subscriptionId -minPublicIP $minPublicIP + + If ($availableIP -le $minPublicIP) { + $requiredIp = $minPublicIP - $availableIP + Write-Host "`n`u{274C} There is not enough Public IP in the $location region to deploy the Jumpstart environment. Need addtional $requiredIp Public IP." -ForegroundColor Red + + $message = "Not enough capacity in $location region." + Throw $message + } else { + Write-Host "`n`u{2705} There is enough VM and Public IP capacity in the $location region to deploy the Jumpstart environment.`n" + } +} + +######################################################################## +# Get Windows Admin Username and Password +######################################################################## +$JS_WINDOWS_ADMIN_USERNAME = 'agora' +if ($promptOutput = Read-Host "Enter the Windows Admin Username [$JS_WINDOWS_ADMIN_USERNAME]") { $JS_WINDOWS_ADMIN_USERNAME = $promptOutput } + +# set the env variable +azd env set JS_WINDOWS_ADMIN_USERNAME -- $JS_WINDOWS_ADMIN_USERNAME + + +######################################################################## +# RDP Port +######################################################################## +$JS_RDP_PORT = '3389' +If ($env:JS_RDP_PORT) { + $JS_RDP_PORT = $env:JS_RDP_PORT +} +if ($promptOutput = Read-Host "Enter the RDP Port for remote desktop connection [$JS_RDP_PORT]") { $JS_RDP_PORT = $promptOutput } + +# set the env variable +azd env set JS_RDP_PORT $JS_RDP_PORT + + +######################################################################## +# GitHub User +######################################################################## +$JS_GITHUB_USER = $env:JS_GITHUB_USER + +$defaultGhUser = "" +If ($JS_GITHUB_USER) { $defaultGhUser = " [$JS_GITHUB_USER]"} + +if ($promptOutput = Read-Host "Enter your GitHub user name$defaultGhUser") { $JS_GITHUB_USER = $promptOutput } + +# set the env variable +azd env set JS_GITHUB_USER -- $JS_GITHUB_USER + + +######################################################################## +# GitHub Personal Access Token +######################################################################## +$JS_GITHUB_PAT = $env:JS_GITHUB_PAT + +$defaultPAT = "" +If ($JS_GITHUB_PAT) { $defaultPAT = " [$JS_GITHUB_PAT]"} + +if ($promptOutput = Read-Host "Enter your GitHub Personal Access Token (PAT)$defaultPAT") { $JS_GITHUB_PAT = $promptOutput } + +# set the env variable +azd env set JS_GITHUB_PAT -- $JS_GITHUB_PAT + + +######################################################################## +# Create SSH RSA Public Key +######################################################################## +Write-Host "Creating SSH RSA Public Key..." +$file = "js_rsa" +remove-item $file, "$file.pub" -Force -ea 0 + +# Generate the SSH key pair +ssh-keygen -q -t rsa -b 4096 -f $file -N '""' + +# Get the public key +$JS_SSH_RSA_PUBLIC_KEY = get-content "$file.pub" + +# Escape the backslashes +$JS_SSH_RSA_PUBLIC_KEY = $JS_SSH_RSA_PUBLIC_KEY.Replace("\", "\\") + +# set the env variable +azd env set JS_SSH_RSA_PUBLIC_KEY -- $JS_SSH_RSA_PUBLIC_KEY + + +######################################################################## +# Create Azure Service Principal +######################################################################## +Write-Host "Creating Azure Service Principal..." + +$user = $context.Account.Id.split("@")[0] +$uniqueSpnName = "$user-jumpstart-spn-$(Get-Random -Minimum 1000 -Maximum 9999)" +try { + $spn = New-AzADServicePrincipal -DisplayName $uniqueSpnName -Role "Owner" -Scope "/subscriptions/$($env:AZURE_SUBSCRIPTION_ID)" -ErrorAction Stop +} +catch { + If ($error[0].ToString() -match "Forbidden"){ + Throw "You do not have permission to create a service principal. Please contact your Azure subscription administrator to grant you the Owner role on the subscription." + } + elseif ($error[0].ToString() -match "credentials") { + Throw "Please run Connect-AzAccount to sign and run 'azd up' again." + } + else { + Throw "An error occurred creating the service principal. Please try again." + } +} + +$SPN_CLIENT_ID = $spn.AppId +$SPN_CLIENT_SECRET = $spn.PasswordCredentials.SecretText +$SPN_TENANT_ID = (Get-AzContext).Tenant.Id + +# Set environment variables +azd env set SPN_CLIENT_ID -- $SPN_CLIENT_ID +azd env set SPN_CLIENT_SECRET -- $SPN_CLIENT_SECRET +azd env set SPN_TENANT_ID -- $SPN_TENANT_ID diff --git a/azure_jumpstart_arcbox/artifacts/WinGet.ps1 b/azure_jumpstart_arcbox/artifacts/WinGet.ps1 index b685bbdf68..b3f1cb71bb 100644 --- a/azure_jumpstart_arcbox/artifacts/WinGet.ps1 +++ b/azure_jumpstart_arcbox/artifacts/WinGet.ps1 @@ -8,8 +8,8 @@ $logFilePath = Join-Path -Path $Env:ArcBoxLogsDir -ChildPath ('WinGet-provisioni Start-Transcript -Path $logFilePath -Force -ErrorAction SilentlyContinue # Install WinGet PowerShell modules -Install-PSResource -Name Microsoft.WinGet.Client -Scope AllUsers -Quiet -AcceptLicense -TrustRepository -Version 1.8.1911 -Install-PSResource -Name Microsoft.WinGet.DSC -Scope AllUsers -Quiet -AcceptLicense -TrustRepository -Prerelease -Version 1.8.1911-alpha +Install-PSResource -Name Microsoft.WinGet.Client -Scope AllUsers -Quiet -AcceptLicense -TrustRepository +Install-PSResource -Name Microsoft.WinGet.DSC -Scope AllUsers -Quiet -AcceptLicense -TrustRepository # Install DSC resources required for ArcBox Install-PSResource -Name DSCR_Font -Scope AllUsers -Quiet -AcceptLicense -TrustRepository @@ -17,7 +17,9 @@ Install-PSResource -Name HyperVDsc -Scope AllUsers -Quiet -AcceptLicense -TrustR Install-PSResource -Name NetworkingDsc -Scope AllUsers -Quiet -AcceptLicense -TrustRepository # Install WinGet CLI -$null = Repair-WinGetPackageManager -AllUsers +$null = Repair-WinGetPackageManager -AllUsers -Force -Latest + +Get-WinGetVersion Write-Header 'Installing WinGet packages and DSC configurations' $winget = Join-Path -Path $env:LOCALAPPDATA -ChildPath Microsoft\WindowsApps\winget.exe diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index 55db440fa5..f972b71c15 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -637,23 +637,6 @@ function Set-NICs { # Rename non-storage adapters Get-NetAdapter ((Get-NetAdapterAdvancedProperty | Where-Object {$_.DisplayValue -eq "SDN"}).Name) | Rename-NetAdapter -NewName FABRIC - # Get-Netadapter ((Get-NetAdapterAdvancedProperty | Where-Object {$_.DisplayValue -eq "SDN2"}).Name) | Rename-NetAdapter -NewName FABRIC2 - - # Enable CredSSP Settings - Invoke-Command -ComputerName localhost -Credential $using:Credential -ScriptBlock { - $fqdn = $Using:HCIBoxConfig.SDNDomainFQDN - - Write-Host "Enabling CredSSP on $env:COMPUTERNAME" - Enable-WSManCredSSP -Role Server -Force - Enable-WSManCredSSP -Role Client -DelegateComputer localhost -Force - Enable-WSManCredSSP -Role Client -DelegateComputer $env:COMPUTERNAME -Force - Enable-WSManCredSSP -Role Client -DelegateComputer $fqdn -Force - Enable-WSManCredSSP -Role Client -DelegateComputer "*.$fqdn" -Force - New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation ` - -Name AllowFreshCredentialsWhenNTLMOnly -Force - New-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly ` - -Name 1 -Value * -PropertyType String -Force - } -InDisconnectedSession | Out-Null } } } diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/WinGet.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/WinGet.ps1 index 7dbdd16122..68f4701f3f 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/WinGet.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/WinGet.ps1 @@ -7,8 +7,8 @@ $logFilePath = Join-Path -Path $Env:HCIBoxLogsDir -ChildPath ('WinGet-provisioni Start-Transcript -Path $logFilePath -Force -ErrorAction SilentlyContinue # Install WinGet PowerShell modules -Install-PSResource -Name Microsoft.WinGet.Client -Scope AllUsers -Quiet -AcceptLicense -TrustRepository -Version 1.8.1911 -Install-PSResource -Name Microsoft.WinGet.DSC -Scope AllUsers -Quiet -AcceptLicense -TrustRepository -Prerelease -Version 1.8.1911-alpha +Install-PSResource -Name Microsoft.WinGet.Client -Scope AllUsers -Quiet -AcceptLicense -TrustRepository +Install-PSResource -Name Microsoft.WinGet.DSC -Scope AllUsers -Quiet -AcceptLicense -TrustRepository # Install DSC resources required for ArcBox Install-PSResource -Name DSCR_Font -Scope AllUsers -Quiet -AcceptLicense -TrustRepository @@ -16,7 +16,9 @@ Install-PSResource -Name HyperVDsc -Scope AllUsers -Quiet -AcceptLicense -TrustR Install-PSResource -Name NetworkingDsc -Scope AllUsers -Quiet -AcceptLicense -TrustRepository # Install WinGet CLI -$null = Repair-WinGetPackageManager -AllUsers +$null = Repair-WinGetPackageManager -AllUsers -Force -Latest + +Get-WinGetVersion Write-Output 'Installing WinGet packages and DSC configurations' $winget = Join-Path -Path $env:LOCALAPPDATA -ChildPath Microsoft\WindowsApps\winget.exe