Public/cloud-hook.ps1

function Get-CloudHook {
    <#
    .SYNOPSIS
        Gets hooks from the Cloud Server.
     
    .DESCRIPTION
        Retrieves a list of hooks. Automatically handles token refresh.
     
    .PARAMETER Name
        Optional. Filter by hook name.
     
    .PARAMETER ID
        Optional. Filter by hook ID
     
    .EXAMPLE
        # Get all hooks
        Get-CloudHook
         
    .EXAMPLE
    # Get a hook by ID
        Get-CloudHook -ID 5
         
    .EXAMPLE
    # Get a hook by name
        Get-CloudHook -Name "vm-creation"
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Name,
        
        [Parameter(Mandatory = $false)]
        [int]$ID
    )
    
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook"
    
    if ($PSBoundParameters.ContainsKey('ID')) {
        $hookuri = "$uri/${ID}"
        $response = Invoke-CloudApiRequest -Uri $hookuri -Method Get
        
        $hook = $response.hook
        return $hook
    }
    else {
        $response = Invoke-CloudApiRequest -Uri $uri -Method Get
        $hooks = $response.hook
        
        if ($Name) {
            $hooks = $hooks | Where-Object { $_.name -like "*$Name*" }
        }
        
        return $hooks
    }
}

function Get-CloudHookLogs {
    <#
    .SYNOPSIS
        Gets hook logs from the Cloud Server.
     
    .DESCRIPTION
        Retrieves hook logs for a specific hook. Automatically handles token refresh.
     
    .PARAMETER HookID
        Hook ID to retrieve logs for
         
    .PARAMETER MinDate
        Minimum date filter (as DateTime object or string)
         
    .PARAMETER MaxDate
        Maximum date filter (as DateTime object or string)
     
    .EXAMPLE
        # Get logs for a hook with a date range
        Get-CloudHookLog -HookID 5 -MinDate "2025-01-01" -MaxDate "2025-01-31"
         
    .EXAMPLE
        # Get logs for a hook for the past 7 days
        Get-CloudHookLog -HookID 5 -MinDate (Get-Date).AddDays(-7) -MaxDate (Get-Date)
         
    .EXAMPLE
        # Get logs for a hook for the past 24 hours
        Get-CloudHookLog -HookID 14 -MinDate (Get-Date).AddDays(-1) -MaxDate (Get-Date)
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [int]$HookID,
        
        [Parameter(Mandatory = $true)]
        [DateTime]$MinDate,
        
        [Parameter(Mandatory = $true)]
        [DateTime]$MaxDate
    )
    
    # Convert dates to YYYY-MM-DD format (Go's date format)
    $minDateStr = $MinDate.ToString("yyyy-MM-dd")
    $maxDateStr = $MaxDate.ToString("yyyy-MM-dd")
    
    # Build the URI with query parameters
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook/$HookID/log"
    $uri += "?min=$minDateStr&max=$maxDateStr"
    
    write-host $uri
    Write-Verbose "Request URI: $uri"
    Write-Verbose "Min Date: $MinDate -> $minDateStr"
    Write-Verbose "Max Date: $MaxDate -> $maxDateStr"
    
    # Use the helper function which handles token refresh automatically
    $response = Invoke-CloudApiRequest -Uri $uri -Method Get
    
    return $response
}

#function New-CloudHook {
# <#
# .SYNOPSIS
# Creates a new hook in the Cloud Server.
#
# .DESCRIPTION
# Creates a hook that triggers on specific events. Automatically handles token refresh.
#
# .PARAMETER Name
# Name of the hook
#
# .PARAMETER Type
# Hook type (e.g., 'api' for API hooks, 'state' for state hooks)
#
# .PARAMETER Command
# Command to execute when hook triggers
#
# .PARAMETER Template
# Full hook template as a string
#
# .EXAMPLE
# # Create a simple logging hook that triggers on VM creation - writes "OpenNebula hook test - VM operation" to the system log (syslog)
# $template = @"
# NAME="simple-test-hook"
# TYPE="api"
# COMMAND="/usr/bin/logger"
# ARGUMENTS="OpenNebula hook test - VM operation"
# CALL="one.vm.allocate"
# "@
# New-CloudHook -Template $template
# #>
#
# [CmdletBinding()]
# param(
# [Parameter(Mandatory = $true)]
# [string]$Template
# )
#
# $hookData = @{
# template = $Template
# }
#
# $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook"
#
# Write-Verbose "Request URI: $uri"
# Write-Verbose "Hook Template:`n$Template"
#
# $response = Invoke-CloudApiRequest -Uri $uri -Method Post -Body $hookData
#
# return $response
#}
#

function Remove-CloudHook {
    <#
    .SYNOPSIS
        Removes a hook from the Cloud Server.
     
    .DESCRIPTION
        Removes a hook. Automatically handles token refresh.
     
    .PARAMETER Name
        Required. Hook ID.
     
    .EXAMPLE
        # Remove hook with confirmation prompt (default behavior):
        Remove-CloudHook -ID 3
        Confirm
        Are you sure you want to perform this action?
        Performing the operation "Remove Hook" on target "Hook ID 3 (MyHook)".
        [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): Y
 
    .EXAMPLE
        # Remove hook without confirmation prompt:
        Remove-CloudHook -ID 3 -Confirm:$false
    #>

    
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [int]$ID
    )
    
    process {
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook/${ID}"
        
        Invoke-CloudResourceRemoval `
            -CallerPSCmdlet $PSCmdlet `
            -ResourceType "Hook" `
            -ID $ID `
            -Uri $uri `
            -GetResourceScript { Get-CloudHook -ID $ID }
    }
}

function Rename-CloudHook {
    <#
    .SYNOPSIS
        Rename a hook in the Cloud Server.
     
    .DESCRIPTION
        Renames a hook. Automatically handles token refresh.
     
    .PARAMETER Name
        New name of the hook
         
    .PARAMETER ID
        ID of the hook
             
    .EXAMPLE
        # Rename a hook
        Rename-CloudHook -Name "new-name" -ID 5
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Name,
        
        [Parameter(Mandatory = $true)]
        [int]$ID
    )
        
    $newname = @{
        name = $Name
    }
    
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook/${ID}/name"
       
    $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -Body $newname
    
    return $response
}

function Lock-CloudHook {
    <#
    .SYNOPSIS
        Lock a hook in the Cloud Server.
     
    .DESCRIPTION
        Lock a hook. Automatically handles token refresh.
        
    .PARAMETER ID
        ID of the hook
 
    .PARAMETER Level
        Lock level (USE, MANAGE, ADMIN, ALL)
 
    .PARAMETER Test
        When set, performs a test lock instead of a real one.
 
    .EXAMPLE
        # Lock a hook to restrict administrative operations
        Lock-CloudHook -ID 5 -Level ADMIN
 
    .EXAMPLE
        # Test locking a hook
        Lock-CloudHook -ID 5 -Level USE -Test
 
    #>

    
    [CmdletBinding()]
    param(
        
        [Parameter(Mandatory = $true)]
        [int]$ID,
        
        [Parameter(Mandatory = $true)]
        [ValidateSet('USE','MANAGE','ADMIN','ALL')]
        [string]$Level,
        
        [switch]$Test
    )

    $lockdata = @{
        level = $Level
        test  = [bool]$Test
    }
    
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook/${ID}/lock"
    $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -Body $lockdata
    return $response
}

function Unlock-CloudHook {
    <#
    .SYNOPSIS
        Unlock a hook in the Cloud Server.
     
    .DESCRIPTION
        Unlock a hook. Automatically handles token refresh.
        
    .PARAMETER ID
        ID of the hook
 
    .EXAMPLE
        # Unlock a hook
        Unlock-CloudHook -ID 5
 
    #>

    
    [CmdletBinding()]
    param(
        
        [Parameter(Mandatory = $true)]
        [int]$ID        

    )
    $unlockdata = @{
        lock = 0
    }
    
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook/${ID}/unlock"
    $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -Body $unlockdata
    return $response
}
 
function New-CloudHook {
    <#
    .SYNOPSIS
        Creates a new hook in the Cloud Server.
     
    .DESCRIPTION
        Creates a hook that triggers on specific OpenNebula events. Hooks can execute commands,
        scripts, or send notifications when specific API calls are made or resource states change.
        Automatically handles token refresh.
     
    .PARAMETER Template
        Required. Hook template in OpenNebula format. Must include NAME, TYPE, COMMAND, and trigger conditions.
         
        Common template attributes:
        - NAME: Hook identifier
        - TYPE: Hook type ('api' or 'state')
        - COMMAND: Command/script to execute
        - ARGUMENTS: Arguments passed to the command ($TEMPLATE for full XML, $ID for resource ID)
        - CALL: API method that triggers the hook (for TYPE=api)
        - ON: State change that triggers the hook (for TYPE=state)
        - RESOURCE: Resource type (VM, HOST, VNET, IMAGE, etc.)
     
    .EXAMPLE
        # Create an API Hook: Log when VMs are created
        $template = @"
NAME="vm-creation-logger"
TYPE="api"
COMMAND="/usr/bin/logger"
ARGUMENTS="VM Created - ID: `$ID"
CALL="one.vm.allocate"
"@
        New-CloudHook -Template $template
         
    .EXAMPLE
        # Create a n API Hook: Send email notification when VM is deleted
        $template = @"
NAME="vm-deletion-alert"
TYPE="api"
COMMAND="/usr/local/bin/send-alert.sh"
ARGUMENTS="`$TEMPLATE"
CALL="one.vm.delete"
"@
        New-CloudHook -Template $template
         
    .EXAMPLE
        # Create a State Hook: Execute script when VM goes to RUNNING state
        $template = @"
NAME="vm-running-webhook"
TYPE="state"
COMMAND="/usr/local/bin/vm-started.sh"
ARGUMENTS="`$ID `$TEMPLATE"
ON="RUNNING"
RESOURCE="VM"
"@
        New-CloudHook -Template $template
         
    .EXAMPLE
        # Create a State Hook: Trigger on VM failure states
        $template = @"
NAME="vm-failure-alert"
TYPE="state"
COMMAND="/usr/local/bin/alert-admin.sh"
ARGUMENTS="VM `$ID failed - `$PREV_STATE to `$CUR_STATE"
ON="FAILED"
RESOURCE="VM"
"@
        New-CloudHook -Template $template
         
    .EXAMPLE
        # Create an API Hook: Monitor host operations
        $template = @"
NAME="host-monitor"
TYPE="api"
COMMAND="/var/lib/one/hooks/host-change.py"
ARGUMENTS="`$ID `$TEMPLATE"
CALL="one.host.update"
"@
        New-CloudHook -Template $template
         
    .EXAMPLE
        # Create a State Hook: Network monitoring
        $template = @"
NAME="network-state-monitor"
TYPE="state"
COMMAND="/usr/local/bin/network-alert.sh"
ARGUMENTS="`$ID"
ON="ERROR"
RESOURCE="VNET"
REMOTE="no"
"@
        New-CloudHook -Template $template
         
    .EXAMPLE
        # Create an API Hook: Image creation tracking with multiple arguments
        $template = @"
NAME="image-creation-tracker"
TYPE="api"
COMMAND="/opt/monitoring/track-image.py"
ARGUMENTS="--image-id `$ID --timestamp `$(date +%s) --user `$UNAME"
CALL="one.image.allocate"
"@
        New-CloudHook -Template $template
    #>

    
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Low')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string]$Template
    )
    
    process {
        $hookData = @{
            template = $Template
        }
        
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook"
        
        if ($PSCmdlet.ShouldProcess("Hook", "Create new hook")) {
            Write-Verbose "Request URI: $uri"
            Write-Verbose "Hook Template:`n$Template"
            
            try {
                $response = Invoke-CloudApiRequest -Uri $uri -Method Post -Body $hookData
                
                Write-Verbose "Successfully created hook: $($response.hook.name)"
                return $response.hook
            }
            catch {
                Write-Error "Failed to create hook: $_"
                throw
            }
        }
    }
} 
 
#function Update-CloudHook1 {
# <#
# .SYNOPSIS
# Updates a hook in the Cloud Server.
#
# .PARAMETER Template
# Required. Hook template in OpenNebula format. Must include NAME, TYPE, COMMAND, and trigger conditions.
#
# .PARAMETER Merge
# Optional. Boolean. Whether or not to merge the config, defaults to true. -Merge:$true or -Merge:$false
#
# .PARAMETER ID
# Required. Hook ID
#
# Common template attributes:
# - NAME: Hook identifier
# - TYPE: Hook type ('api' or 'state')
# - COMMAND: Command/script to execute
# - ARGUMENTS: Arguments passed to the command ($TEMPLATE for full XML, $ID for resource ID)
# - CALL: API method that triggers the hook (for TYPE=api)
# - ON: State change that triggers the hook (for TYPE=state)
# - RESOURCE: Resource type (VM, HOST, VNET, IMAGE, etc.)
#
# .EXAMPLE
# # API Hook: Log when VMs are created
# $template = @"
#NAME="vm-creation-logger"
#TYPE="api"
#COMMAND="/usr/bin/logger"
#ARGUMENTS="VM Created - ID: `$ID"
#CALL="one.vm.allocate"
#"@
# Update-CloudHook -ID 5 -Template $template
#
# .EXAMPLE
# # API Hook: Send email notification when VM is deleted
# $template = @"
#NAME="vm-deletion-alert"
#TYPE="api"
#COMMAND="/usr/local/bin/send-alert.sh"
#ARGUMENTS="`$TEMPLATE"
#CALL="one.vm.delete"
#"@
# Update-CloudHook -ID 5 -Template $template
#
# .EXAMPLE
# # State Hook: Execute script when VM goes to RUNNING state
# $template = @"
#NAME="vm-running-webhook"
#TYPE="state"
#COMMAND="/usr/local/bin/vm-started.sh"
#ARGUMENTS="`$ID `$TEMPLATE"
#ON="RUNNING"
#RESOURCE="VM"
#"@
# Update-CloudHook -ID 5 -Template $template
#
# .EXAMPLE
# # State Hook: Trigger on VM failure states
# $template = @"
#NAME="vm-failure-alert"
#TYPE="state"
#COMMAND="/usr/local/bin/alert-admin.sh"
#ARGUMENTS="VM `$ID failed - `$PREV_STATE to `$CUR_STATE"
#ON="FAILED"
#RESOURCE="VM"
#"@
# Update-CloudHook -ID 5 -Template $template
#
# .EXAMPLE
# # API Hook: Monitor host operations
# $template = @"
#NAME="host-monitor"
#TYPE="api"
#COMMAND="/var/lib/one/hooks/host-change.py"
#ARGUMENTS="`$ID `$TEMPLATE"
#CALL="one.host.update"
#"@
# Update-CloudHook -ID 5 -Template $template
#
# .EXAMPLE
# # State Hook: Network monitoring
# $template = @"
#NAME="network-state-monitor"
#TYPE="state"
#COMMAND="/usr/local/bin/network-alert.sh"
#ARGUMENTS="`$ID"
#ON="ERROR"
#RESOURCE="VNET"
#REMOTE="no"
#"@
# Update-CloudHook -ID 5 -Template $template
#
# .EXAMPLE
# # API Hook: Image creation tracking with multiple arguments and will not merge the config
# $template = @"
#NAME="image-creation-tracker"
#TYPE="api"
#COMMAND="/opt/monitoring/track-image.py"
#ARGUMENTS="--image-id `$ID --timestamp `$(date +%s) --user `$UNAME"
#CALL="one.image.allocate"
#"@
# Update-CloudHook -ID 5 -Template $template -Merge:$false
# #>
#
#[CmdletBinding(SupportsShouldProcess, ConfirmImpact='Low')]
#param(
# [Parameter(Mandatory = $true)]
# [int]$ID,
#
# [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
# [string]$Template,
#
# [Parameter()]
# [bool]$Merge = $true
#)
#
#process {
# $hookData = @{
# merge = $Merge
# template = $Template
# }
#
# $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook/${ID}"
# Write-Host "DEBUG - Body being sent:"
#$hookData | ConvertTo-Json -Depth 5 | Write-Host
#
# if ($PSCmdlet.ShouldProcess("Hook ID $ID", "Update hook")) {
# Write-Verbose "Request URI: $uri"
# Write-Verbose "Hook Template:`n$Template"
# Write-Verbose "Merge: $Merge"
#
# try {
# $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -Body $hookData
#
# Write-Verbose "Successfully updated hook $ID"
# return $response.hook
# }
# catch {
# Write-Error "Failed to update hook: $_"
# throw
# }
# }
#}
#}
#
 function Update-CloudHook {
    <#
    .SYNOPSIS
        Updates a hook in the Cloud Server.
        
    .PARAMETER ID
        Required. Hook ID to update
         
    .PARAMETER Template
        Required. Hook template in OpenNebula format.
     
    .PARAMETER Merge
        Optional. If specified, merges with existing template. If not specified, replaces the template entirely.
         
    .EXAMPLE
        # Update a hook replacing the entire hook configuration (default behavior)
        $template = @"
NAME="new-hook-name"
TYPE="api"
COMMAND="/usr/bin/logger"
ARGUMENTS="Test"
CALL="one.vm.allocate"
"@
        Update-CloudHook -ID 17 -Template $template
         
    .EXAMPLE
        # Update a book merging the new configuration with the existing configuration
        $template = 'ARGUMENTS="New arguments"'
        Update-CloudHook -ID 17 -Template $template -Merge
    #>

    
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Low')]
    param(
        [Parameter(Mandatory = $true)]
        [int]$ID,
        
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string]$Template,
        
        [Parameter()]
        [switch]$Merge
    )
    
    process {
        # Build the request body
        $hookData = @{
            template = $Template
        }
        
        if ($Merge) {
            $hookData['merge'] = $true
        }
        
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook/${ID}"
        
        if ($PSCmdlet.ShouldProcess("Hook ID $ID", "Update hook")) {
            Write-Verbose "Request URI: $uri"
            Write-Verbose "Hook Template:`n$Template"
            Write-Verbose "Merge: $Merge"
            
            try {
                $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -Body $hookData
                
                Write-Verbose "Successfully updated hook $ID"
                return $response.hook
            }
            catch {
                Write-Error "Failed to update hook: $_"
                throw
            }
        }
    }
}

function Redo-CloudHook {
    <#
    .SYNOPSIS
        Attempt to retry a hook in the Cloud Server.
     
    .DESCRIPTION
        Retries a hook. Automatically handles token refresh.
          
    .PARAMETER ID
        Required. ID of the hook
         
    .PARAMETER Time
        Required. Time in seconds to wait before retrying the hook
         
    .EXAMPLE
        # Retries hook 5 in 10 seconds
        Redo-CloudHook -ID 5 -Time 10
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [int]$Time,
        
        [Parameter(Mandatory = $true)]
        [int]$ID
    )
        
    $hooktime = @{
        execution = $Time
    }
    
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/hook/${ID}/retry"
       
    $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -Body $hooktime
    
    return $response
}