modules/HomeLab.Monitoring/Public/Monitoring.ps1

<#
.SYNOPSIS
    Starts monitoring Azure resources.
.DESCRIPTION
    Starts monitoring Azure resources by setting up a background job that collects metrics at regular intervals.
.PARAMETER ResourceGroup
    The name of the resource group to monitor. If not specified, all resources in the subscription will be monitored.
.PARAMETER IntervalMinutes
    The interval in minutes at which to collect metrics. Default is 15 minutes.
.EXAMPLE
    Start-ResourceMonitoring -ResourceGroup "HomeLab-RG" -IntervalMinutes 5
#>

function Start-ResourceMonitoring {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [string]$ResourceGroup,
        
        [Parameter(Mandatory = $false)]
        [int]$IntervalMinutes = 15
    )
    
    begin {
        # Import required modules
        Import-Module HomeLab.Core
        Import-Module HomeLab.Azure
        
        # Get configuration
        $config = Get-Configuration
        
        # Log function start
        Write-Log -Message "Starting resource monitoring" -Level INFO
    }
    
    process {
        try {
            # Check if Azure is connected
            if (-not (Test-AzureConnection)) {
                Connect-AzureAccount
            }
            
            # If no resource group is specified, use the one from config
            if (-not $ResourceGroup) {
                $ResourceGroup = "$($config.projectName)-$($config.env)-$($config.locationCode)-rg"
            }
            
            # Check if the resource group exists
            $rgExists = Get-AzResourceGroup -Name $ResourceGroup -ErrorAction SilentlyContinue
            if (-not $rgExists) {
                throw "Resource group $ResourceGroup does not exist"
            }
            
            # Start a background job to monitor resources
            $jobScript = {
                param($ResourceGroup, $IntervalMinutes, $ConfigPath)
                
                # Import required modules
                Import-Module HomeLab.Core
                Import-Module HomeLab.Azure
                Import-Module Az.Monitor
                
                # Load configuration
                Initialize-Configuration -Path $ConfigPath
                
                while ($true) {
                    try {
                        # Get all resources in the resource group
                        $resources = Get-AzResource -ResourceGroupName $ResourceGroup
                        
                        foreach ($resource in $resources) {
                            # Get metrics for the resource
                            $metrics = Get-AzMetric -ResourceId $resource.Id -MetricName "Percentage CPU" -TimeGrain 00:05:00 -DetailedOutput
                            
                            # Log the metrics
                            Write-Log -Message "Resource: $($resource.Name), Type: $($resource.ResourceType), CPU: $($metrics.Data.Average)" -Level INFO
                            
                            # Check if metrics exceed thresholds and trigger alerts if needed
                            if ($metrics.Data.Average -gt 80) {
                                Write-Log -Message "HIGH CPU ALERT: Resource $($resource.Name) has CPU usage of $($metrics.Data.Average)%" -Level WARNING
                                # TODO: Implement alerting mechanism
                            }
                        }
                    }
                    catch {
                        Write-Log -Message "Error monitoring resources: $_" -Level ERROR
                    }
                    
                    # Wait for the specified interval
                    Start-Sleep -Seconds ($IntervalMinutes * 60)
                }
            }
            
            # Start the background job
            $job = Start-Job -ScriptBlock $jobScript -ArgumentList $ResourceGroup, $IntervalMinutes, $config.configPath
            
            # Store the job ID in the configuration
            $config.monitoringJobId = $job.Id
            Save-Configuration
            
            Write-Log -Message "Resource monitoring started with job ID $($job.Id)" -Level INFO
            return $job
        }
        catch {
            Write-Log -Message "Failed to start resource monitoring: $_" -Level ERROR
            throw $_
        }
    }
    
    end {
        # Log function end
        Write-Log -Message "Resource monitoring setup completed" -Level INFO
    }
}

<#
.SYNOPSIS
    Gets performance metrics for Azure resources.
.DESCRIPTION
    Gets performance metrics for Azure resources in the specified resource group.
.PARAMETER ResourceGroup
    The name of the resource group. If not specified, the resource group from the configuration will be used.
.PARAMETER ResourceType
    The type of resource to get metrics for. If not specified, all resource types will be included.
.PARAMETER TimeGrain
    The time grain for the metrics. Default is 1 hour.
.PARAMETER StartTime
    The start time for the metrics. Default is 24 hours ago.
.PARAMETER EndTime
    The end time for the metrics. Default is the current time.
.EXAMPLE
    Get-ResourceMetrics -ResourceGroup "HomeLab-RG" -ResourceType "Microsoft.Compute/virtualMachines"
#>

function Get-ResourceMetrics {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [string]$ResourceGroup,
        
        [Parameter(Mandatory = $false)]
        [string]$ResourceType,
        
        [Parameter(Mandatory = $false)]
        [string]$TimeGrain = "01:00:00",
        
        [Parameter(Mandatory = $false)]
        [datetime]$StartTime = (Get-Date).AddHours(-24),
        
        [Parameter(Mandatory = $false)]
        [datetime]$EndTime = (Get-Date)
    )
    
    begin {
        # Import required modules
        Import-Module HomeLab.Core
        Import-Module HomeLab.Azure
        
        # Get configuration
        $config = Get-Configuration
        
        # Log function start
        Write-Log -Message "Getting resource metrics" -Level INFO
    }
    
    process {
        try {
            # Check if Azure is connected
            if (-not (Test-AzureConnection)) {
                Connect-AzureAccount
            }
            
            # If no resource group is specified, use the one from config
            if (-not $ResourceGroup) {
                $ResourceGroup = "$($config.projectName)-$($config.env)-$($config.locationCode)-rg"
            }
            
            # Get resources based on the specified filters
            $resourceFilter = @{
                ResourceGroupName = $ResourceGroup
            }
            
            if ($ResourceType) {
                $resourceFilter.ResourceType = $ResourceType
            }
            
            $resources = Get-AzResource @resourceFilter
            
            $results = @()
            
            foreach ($resource in $resources) {
                # Get available metrics for the resource
                $availableMetrics = Get-AzMetricDefinition -ResourceId $resource.Id
                
                # Get common metrics based on resource type
                $metricsToGet = @()
                
                switch -Wildcard ($resource.ResourceType) {
                    "Microsoft.Compute/virtualMachines" {
                        $metricsToGet = @("Percentage CPU", "Available Memory Bytes", "Disk Read Bytes", "Disk Write Bytes", "Network In", "Network Out")
                    }
                    "Microsoft.Network/virtualNetworkGateways" {
                        $metricsToGet = @("AverageBandwidth", "P2SBandwidth", "P2SConnectionCount", "TunnelEgressBytes", "TunnelIngressBytes")
                    }
                    "Microsoft.Network/natGateways" {
                        $metricsToGet = @("ByteCount", "PacketCount", "DroppedPacketCount")
                    }
                    default {
                        # For other resource types, just get the first 3 available metrics
                        $metricsToGet = $availableMetrics | Select-Object -First 3 | ForEach-Object { $_.Name.Value }
                    }
                }
                
                # Filter metrics to only those that are available for the resource
                $availableMetricNames = $availableMetrics | ForEach-Object { $_.Name.Value }
                $metricsToGet = $metricsToGet | Where-Object { $_ -in $availableMetricNames }
                
                $resourceMetrics = @{
                    ResourceName = $resource.Name
                    ResourceType = $resource.ResourceType
                    Metrics = @{}
                }
                
                foreach ($metricName in $metricsToGet) {
                    $metric = Get-AzMetric -ResourceId $resource.Id -MetricName $metricName -TimeGrain $TimeGrain -StartTime $StartTime -EndTime $EndTime -DetailedOutput
                    
                    $metricData = @{
                        Name = $metricName
                        Unit = $metric.Unit
                        Data = $metric.Data | Select-Object TimeStamp, Average, Minimum, Maximum
                    }
                    
                    $resourceMetrics.Metrics[$metricName] = $metricData
                }
                
                $results += $resourceMetrics
            }
            
            return $results
        }
        catch {
            Write-Log -Message "Failed to get resource metrics: $_" -Level ERROR
            throw $_
        }
    }
    
    end {
        # Log function end
        Write-Log -Message "Resource metrics retrieved successfully" -Level INFO
    }
}

<#
.SYNOPSIS
    Tests the health of Azure resources.
.DESCRIPTION
    Tests the health of Azure resources in the specified resource group.
.PARAMETER ResourceGroup
    The name of the resource group. If not specified, the resource group from the configuration will be used.
.EXAMPLE
    Test-ResourceHealth -ResourceGroup "HomeLab-RG"
#>

function Test-ResourceHealth {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [string]$ResourceGroup
    )
    
    begin {
        # Import required modules
        Import-Module HomeLab.Core
        Import-Module HomeLab.Azure
        
        # Get configuration
        $config = Get-Configuration
        
        # Log function start
        Write-Log -Message "Testing resource health" -Level INFO
    }
    
    process {
        try {
            # Check if Azure is connected
            if (-not (Test-AzureConnection)) {
                Connect-AzureAccount
            }
            
            # If no resource group is specified, use the one from config
            if (-not $ResourceGroup) {
                $ResourceGroup = "$($config.projectName)-$($config.env)-$($config.locationCode)-rg"
            }
            
            # Get all resources in the resource group
            $resources = Get-AzResource -ResourceGroupName $ResourceGroup
            
            $healthResults = @()
            
            foreach ($resource in $resources) {
                try {
                    # Get resource health
                    $health = Get-AzHealthResource -ResourceId $resource.Id -ErrorAction SilentlyContinue
                    
                    if ($health) {
                        $healthStatus = $health.Properties.availabilityState
                    }
                    else {
                        $healthStatus = "Unknown"
                    }
                    
                    # Get additional status information based on resource type
                    $statusInfo = $null
                    
                    switch -Wildcard ($resource.ResourceType) {
                        "Microsoft.Compute/virtualMachines" {
                            $vm = Get-AzVM -ResourceGroupName $ResourceGroup -Name $resource.Name -Status
                            $statusInfo = $vm.Statuses | Where-Object { $_.Code -like "PowerState*" } | ForEach-Object { $_.DisplayStatus }
                        }
                        "Microsoft.Network/virtualNetworkGateways" {
                            $gateway = Get-AzVirtualNetworkGateway -ResourceGroupName $ResourceGroup -Name $resource.Name
                            $statusInfo = $gateway.ProvisioningState
                        }
                        "Microsoft.Network/natGateways" {
                            $natGateway = Get-AzNatGateway -ResourceGroupName $ResourceGroup -Name $resource.Name
                            $statusInfo = $natGateway.ProvisioningState
                        }
                        default {
                            $statusInfo = "Not available"
                        }
                    }
                    
                    $healthResults += [PSCustomObject]@{
                        ResourceName = $resource.Name
                        ResourceType = $resource.ResourceType
                        HealthStatus = $healthStatus
                        StatusInfo = $statusInfo
                        LastUpdated = Get-Date
                    }
                }
                catch {
                    Write-Log -Message "Failed to get health for resource $($resource.Name): $_" -Level WARNING
                    
                    $healthResults += [PSCustomObject]@{
                        ResourceName = $resource.Name
                        ResourceType = $resource.ResourceType
                        HealthStatus = "Error"
                        StatusInfo = $_.Exception.Message
                        LastUpdated = Get-Date
                    }
                }
            }
            
            return $healthResults
        }
        catch {
            Write-Log -Message "Failed to test resource health: $_" -Level ERROR
            throw $_
        }
    }
    
    end {
        # Log function end
        Write-Log -Message "Resource health test completed" -Level INFO
    }
}