> For the complete documentation index, see [llms.txt](https://jadelab.gitbook.io/jadegit/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jadelab.gitbook.io/jadegit/0.18.0/admin/database-snapshots/example.md).

# Example

Taking a snapshot of a database involves various factors beyond the scope of this documentation, including infrastructure dependencies and operational requirements that will vary between teams. Instead, the following example focuses on the consumer side, illustrating how snapshots may be resolved and downloaded from Azure Blob Storage during Azure DevOps pipelines.

The templates are part of the same broader admin repository introduced in the Database Images example, with snapshot templates organised under their own folder reflecting the same separation of concerns.

```
ci/
  ...
images/
  ...
migration/
  ...
snapshot/
  pipeline.yml (not covered)
  download.yml
  resolve.yml
```

## Resolve

The `resolve.yml` template resolves a snapshot reference to a specific snapshot name, verifying that it exists before making it available to subsequent steps via the `snapshot.name` variable.

When the `codeonly` parameter is set and the reference is `latest`, it is automatically redirected to `code`, ensuring the most recent offline or quiesced snapshot is resolved rather than the most recent full snapshot.

If the reference matches a reference file, its contents are read to determine the snapshot name. Otherwise the reference is used directly as the snapshot name. In either case, the snapshot is then verified to exist by checking for the presence of `_monitor.dat` in its system folder.

```yaml
parameters:
- name: snapshot
  type: object

- name: codeonly
  type: boolean
  default: false

steps:
- task: AzureCLI@2  
  displayName: 'Resolve Snapshot'
  inputs:
    azureSubscription: ${{ parameters.snapshot.subscription }}
    scriptType: 'ps'
    scriptLocation: 'inlineScript'
    inlineScript: |      
      $snapshot_reference = "${{ parameters.snapshot.reference }}"
      if ("${{ parameters.codeonly }}" -eq $true -and $snapshot_reference -eq "latest")
      {
        $snapshot_reference = "code"
      }
      
      Write-Host "Resolving snapshot reference (${snapshot_reference})"
      $exists = az storage blob exists --account-name ${{ parameters.snapshot.storage }} --auth-mode login --container-name ${{ parameters.snapshot.environment }} --name "${{ parameters.snapshot.database }}/${snapshot_reference}.txt"
      if ($LASTEXITCODE -ne 0)
      {
        Write-Host "##vso[task.logissue type=error]Failed to check if snapshot reference exists"
        exit $LASTEXITCODE
      }

      if (($exists | ConvertFrom-Json).exists)
      {
        az storage copy --auth-mode login -s "https://${{ parameters.snapshot.storage }}.blob.core.windows.net/${{ parameters.snapshot.environment }}/${{ parameters.snapshot.database }}/${snapshot_reference}.txt" -d "$(Agent.TempDirectory)\snapshot_reference.txt"
        if ($LASTEXITCODE -ne 0)
        {
          Write-Host "##vso[task.logissue type=error]Failed to download snapshot reference file"
          exit $LASTEXITCODE
        }
        $snapshot_name = Get-Content "$(Agent.TempDirectory)\snapshot_reference.txt"
      }
      else
      {
        $snapshot_name = $snapshot_reference
      }

      Write-Host "Checking snapshot exists (${snapshot_name})"
      $exists = az storage blob exists --account-name ${{ parameters.snapshot.storage }} --auth-mode login --container-name ${{ parameters.snapshot.environment }} --name "${{ parameters.snapshot.database }}/${snapshot_name}/system/_monitor.dat"
      if ($LASTEXITCODE -ne 0)
      {
        Write-Host "##vso[task.logissue type=error]Failed to check if snapshot exists"
        exit $LASTEXITCODE
      }

      if (($exists | ConvertFrom-Json).exists)
      {
        Write-Host "Snapshot appears to exist"
        Write-Host "##vso[task.setvariable variable=snapshot.name]$snapshot_name"
      }
      else
      {
        Write-Host "##vso[task.logissue type=error]Snapshot doesn't exist"
        exit 1
      }
```

## Download

The `download.yml` template downloads a snapshot, as specified by the `snapshot` parameter, which contains the source environment, database, and reference.

When the `codeonly` parameter is set, journals and non-system data files are excluded from the download, resulting in a copy of the database that doesn't contain any application data. The `jdbutilb` database utility is then used to reset the database to a usable state, which involves a series of commands to clear the current database role, remove references to the excluded files, and put it into non-production mode.

```yaml
parameters:
- name: path
  type: string

- name: snapshot
  type: object

- name: codeonly
  type: boolean
  default: false

steps:
- template: resolve.yml
  parameters:
    snapshot: ${{ parameters.snapshot }}
    codeonly: ${{ parameters.codeonly }}

- task: AzureCLI@2
  displayName: 'Download Snapshot'
  inputs:
    azureSubscription: ${{ parameters.snapshot.subscription }}
    scriptType: 'ps'
    scriptLocation: 'inlineScript'
    inlineScript: |
      az config set extension.use_dynamic_install=yes_without_prompt
      $opts = @()
      $extra_opts = @()
      if ("${{ parameters.codeonly }}" -eq $true)
      {
        $opts += @('--exclude-path', 'system/journals')
        $extra_opts += @('--exclude-regex', 'system\/["^"_].*')
      }
      az storage copy -s "https://${{ parameters.snapshot.storage }}.blob.core.windows.net/${{ parameters.snapshot.environment }}/${{ parameters.snapshot.database }}/$(snapshot.name)/*" -d "${{ parameters.path }}" --auth-mode login --recursive $opts -- $extra_opts

- ${{ if eq(parameters.codeonly, true) }}:
  - powershell: |
      Out-File -FilePath "jade.ini"
      $commands = "$(Agent.TempDirectory)\reset-commands.txt"
      "showInfo", "clearRole", "productionMode=false", "delete _environ", "recover" | Out-File -FilePath $commands
      (bin\jdbutilb path=system ini=".\jade.ini" listFiles) |
        Select-String -Pattern '(?m)^#\d*\s*.\s*..\s*(?<file>[^_][^\s]*).*No file$' |
          ForEach-Object {
            Write-Output "delete $($_.Matches[0].Groups[1].Value)";
          } | Out-File -Append -FilePath $commands
      bin\jdbutilb path=system ini=".\jade.ini" commandFile=$commands
      bin\jdbutilb path=system ini=".\jade.ini" showInfo
      bin\jdbutilb path=system ini=".\jade.ini" touchDB
    displayName: "Reset Database"
    workingDirectory: ${{ parameters.path }}
```
