This repository hosts Parallels RAS Custom Provider Framework (CPF) samples, one
folder per platform (proxmox/, OpenShift/, hpe-vme/). This guide explains
how to add a new provider folder. Read the repository README for
the framework overview first.
Everything here is provided as is, without warranty of any kind, under the MIT License. By contributing you agree your contribution is licensed the same way. See the disclaimer in the README.
This project follows a Code of Conduct. By participating you are expected to uphold it.
Create one folder per platform, lowercase, named after the platform. Mirror the existing providers:
<platform>/
Parallels-RAS-CFP-<Platform>.ps1 Provider script (CPF JSON-RPC over stdio)
README.md Provider docs (config, capabilities, methods)
<Platform>-API.md Optional: the target platform's API surface used
tests/
Test-<Platform>.ps1 Optional: a dedicated end-to-end test
- Provider script name:
Parallels-RAS-CFP-<Platform>.ps1. - Keep platform-specific files inside the folder. The shared harness
(
CustomProvider.psd1,CustomProvider.psm1) and the genericTest-*.ps1scripts inproxmox/tests/stay where they are and work for any provider.
Copy basic/Parallels-RAS-CFP-Basic.ps1 as a starting point. It
shows the minimal shape: a method registry, request validation, a
Send-Response writer, and the stdin read loop. Build the platform logic around
that.
Requirements:
- PowerShell 7 or later.
Set-StrictMode -Version Latestis recommended; guard optional property reads with a presence check so missing fields return a clean CPF error instead of throwing.- Never write anything to stdout except a single JSON response object per request. Send logs to a file, never to stdout.
Each request is one JSON object on stdin; reply with one JSON object on stdout.
A success reply has a result; a failure reply has an error with code and
message. Encode identifiers, control values, IPs and MACs as strings.
Implement these methods (see the per-provider READMEs for working examples):
| Method | Returns | Notes |
|---|---|---|
provider/initialize |
result.version, result.capabilities |
Static; advertises capabilities (below) |
provider/connect |
result ({} or a message) |
Validate params.settings; open the session |
provider/disconnect |
result |
Clear session state |
guests/list |
result.guests (array of string IDs) |
|
guests/get |
result guest object |
name, state, ip_addresses, mac_addresses, is_template |
guests/control |
result ({}) |
start, stop, reset, restart, suspend, delete |
guests/convert |
result.task_id |
is_template true/false |
guests/clone |
result.task_id (+ optional clone_id) |
source VM or snapshot |
guests/snapshots/create |
result.task_id |
|
guests/snapshots/delete |
result.task_id |
|
guests/snapshots/exists |
result (boolean) |
|
guests/snapshots/revert |
result.task_id |
|
tasks/get |
result.state (+ result.output / result.error) |
running / completed / failed |
Power-state values returned by guests/get: powered_off, powering_off,
powered_on, powering_on, suspended, suspending. Map the platform's native
states onto these.
provider/initialize advertises what the provider supports, for example:
@{
version = '1.0.0'
capabilities = @{
can_suspend_guests = $true
guests_polling_rate = 5
tasks_polling_rate = 10
tasks_polling_retries = 180
template_method = 'versioning' # or omit for the simplified image/template model
can_link_clones = $false
}
}Only advertise suspend if guests/control actually implements it. For
platforms without native snapshots, use the image/template mapping described in
the CPF "Capabilities" documentation instead of versioning.
Long-running operations (clone, snapshot, restore, convert) return a task_id.
RAS then polls tasks/get until the state is completed or failed. Encode
enough information in the task_id to resolve status later (the OpenShift
provider, for example, encodes the object kind, namespace and name).
Providers are launched through the shared manifest. A test/local config:
@{
CommandPath = 'C:\Program Files\PowerShell\7\pwsh.exe'
CommandArgs = '-File "C:\Work\Custom-Provider\<platform>\Parallels-RAS-CFP-<Platform>.ps1"'
CustomSettings = @{
# platform connection settings passed to provider/connect
}
}In the RAS Console, add the provider under
Farm > Site > Providers > Add > Custom Provider, mark secrets (tokens,
passwords) as secure variables.
Point CustomProvider.psd1 at the new script and run the shared harness:
pwsh -File proxmox/tests/Test-Connect.ps1
pwsh -File proxmox/tests/Test-GuestsList.ps1A dedicated, parameterized test under <platform>/tests/ is encouraged (see
OpenShift/tests/Test-OpenShift.ps1). If it resolves the provider script or the
shared module by relative path, compute those from $PSScriptRoot so the test
works from its subfolder.
Before opening a PR, confirm the script parses with no errors:
$e=$null;$t=$null
[System.Management.Automation.Language.Parser]::ParseFile('<platform>/Parallels-RAS-CFP-<Platform>.ps1',[ref]$t,[ref]$e)
$e- Add
<platform>/README.md: files, requirements,CustomProvider.psd1configuration, supported methods, capabilities, sample requests, and any limitations. Link back to the root README. - Add the provider to the Providers table in the root README.md.
- If you document the platform API, put it in
<platform>/<Platform>-API.mdand cite official sources.
- Treat tokens, passwords and API keys as secrets: use least-privilege credentials, keep secrets out of the scripts, and mark them as secure variables in RAS.
- Default to validating TLS in production; if a sample skips certificate checks for convenience, make it a setting and document it.
- Match the existing scripts: PascalCase functions,
Set-StrictMode, structured CPF error responses, file-based logging. - Keep commits focused and describe what changed and why. Open a PR against
main; each provider folder should be self-contained.
Copy this into your pull request and tick each item. It mirrors sections 1 to 8 above.
Layout and naming
- New folder
<platform>/, lowercase, named after the platform - Provider script named
Parallels-RAS-CFP-<Platform>.ps1 - Platform-specific files kept inside the folder; the shared harness untouched
Protocol
- One JSON object per request on stdin, one JSON response per line on stdout
- Nothing else is written to stdout (logs go to a file)
- Success replies carry
result; failures carryerrorwithcodeandmessage - Identifiers, control values, IPs and MACs are encoded as strings
- All applicable CPF methods implemented (
provider/*,guests/*,tasks/get) -
guests/getreturnsname,state,ip_addresses,mac_addresses,is_template - Native power states mapped to the standard values (
powered_off,powering_off,powered_on,powering_on,suspended,suspending)
Capabilities
-
provider/initializeadvertises accurate capabilities and aversion -
can_suspend_guestsonly set whenguests/controlimplements suspend -
template_methodmatches reality (versioning, the image/template model, or omitted) -
can_link_clonesreflects actual support
Asynchronous tasks
- Long-running ops (clone, convert, snapshot, revert) return a
task_id -
task_idencodes enough to resolve status intasks/get -
tasks/getreturnsrunning/completed/failed
Configuration
- Works when launched via
CustomProvider.psd1(CommandPath / CommandArgs / CustomSettings) - Connection settings consumed in
provider/connect, secrets marked as secure variables
Testing
- Script parses with no errors (
Parser::ParseFile, see section 5) - Verified against the shared harness (
proxmox/tests/Test-*.ps1) - Optional: a dedicated
<platform>/tests/Test-<Platform>.ps1, paths resolved from$PSScriptRoot - Validation status stated honestly (tested against a live system, or sample only)
Documentation
-
<platform>/README.mdadded (files, requirements, config, methods, capabilities, limitations) - Provider added to the Providers table in the root README.md
- Optional
<platform>/<Platform>-API.mdcites official sources - "Provided as is, without warranty" note included, linking the root README and LICENSE
Security
- No tokens, passwords or API keys committed (use least-privilege, secure variables)
- TLS validation defaults to on; any certificate-check skip is an opt-in, documented setting
Style and PR
- Matches existing scripts (PascalCase functions,
Set-StrictMode, structured CPF errors, file logging) - Provider folder is self-contained; PR opened against
mainwith a clear description