Add Octopus Deploy Platform Hub knowledge base

New files:
- PLATFORMHUB.md: index for Platform Hub guidance
- platformhub/architecture.md: Git→PlatformHub→Projects model
- platformhub/ocl-syntax.md: complete OCL reference for templates
- platformhub/process-template-patterns.md: 5 proven patterns
- platformhub/gotchas.md: every error hit and how to fix it
- platformhub/api-reference.md: API vs UI capabilities
- best-practices/octopus-process-templates.md: consolidated best practices

Learned from building PlatformHub-Demo (30 microservices, 3 clouds).
Key discoveries: step templates are space-scoped (can't cross-reference),
worker_pool parameter is mandatory, publishing/sharing is UI-only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul O'Reilly
2026-03-25 09:54:09 +13:00
parent 752fdfd82e
commit 6c0f2db169
8 changed files with 1116 additions and 0 deletions

View File

@@ -0,0 +1,189 @@
# Platform Hub API Reference
What can and cannot be managed via the Octopus Deploy API versus the UI.
## API-Manageable Resources
These can be created, read, updated, and deleted via the REST API:
| Resource | Endpoint | Notes |
|----------|----------|-------|
| Spaces | `POST /api/spaces` | Requires `SpaceManagersTeamMembers` |
| Environments | `POST /api/{SpaceId}/environments` | |
| Lifecycles | `POST /api/{SpaceId}/lifecycles` | Include phase definitions |
| Project Groups | `POST /api/{SpaceId}/projectgroups` | |
| Docker Feeds | `POST /api/{SpaceId}/feeds` | `FeedType: "Docker"` |
| Step Templates | `POST /api/{SpaceId}/actiontemplates` | Space-scoped |
| Projects | `POST /api/{SpaceId}/projects` | |
| Channels | `POST /api/{SpaceId}/channels` | With lifecycle assignment |
| Releases | `POST /api/{SpaceId}/releases` | With channel and package selection |
| Runbooks | `POST /api/{SpaceId}/runbooks` | |
| Deployment Processes | `GET/PUT /api/{SpaceId}/deploymentprocesses/{id}` | |
| Variables | `GET/PUT /api/{SpaceId}/variables/{id}` | |
## UI-Only Operations
These **cannot** be done via API or CLI — must use the Octopus web UI:
| Operation | Why |
|-----------|-----|
| **Publish process template** (create version) | Platform Hub feature, no API endpoint |
| **Share process template** with spaces | Platform Hub feature, no API endpoint |
| **Configure Platform Hub Git connection** | Instance-level setting |
| **Convert project to Config as Code** | `POST .../git/convert` exists but requires Git credentials interactively |
## Common API Patterns
### Authentication
All API calls require the `X-Octopus-ApiKey` header:
```bash
API_KEY=$(grep 'value:' ~/dev/claude/secrets/taniwha.octopus.app/api_key | awk '{print $2}')
curl -s -H "X-Octopus-ApiKey: $API_KEY" \
"https://taniwha.octopus.app/api/Spaces-103/environments"
```
### Create a Space
```bash
curl -s -H "X-Octopus-ApiKey: $API_KEY" \
-H "Content-Type: application/json" \
-X POST "https://taniwha.octopus.app/api/spaces" \
-d '{
"Name": "My Space",
"SpaceManagersTeamMembers": ["Users-21"],
"IsDefault": false
}'
```
Note: `SpaceManagersTeamMembers` must not be empty — at least one user or team required.
### Create Environments
```bash
for env in Development Staging Production; do
curl -s -H "X-Octopus-ApiKey: $API_KEY" \
-H "Content-Type: application/json" \
-X POST "https://taniwha.octopus.app/api/$SPACE_ID/environments" \
-d "{\"Name\": \"$env\"}"
done
```
### Create Lifecycles with Auto-Deploy Phases
```bash
# Non-Prod: Dev → Staging (auto-deploy both)
curl -s -H "X-Octopus-ApiKey: $API_KEY" \
-H "Content-Type: application/json" \
-X POST "https://taniwha.octopus.app/api/$SPACE_ID/lifecycles" \
-d '{
"Name": "Non-Prod",
"Phases": [
{
"Name": "Development",
"AutomaticDeploymentTargets": ["Environments-104"],
"OptionalDeploymentTargets": [],
"MinimumEnvironmentsBeforePromotion": 0,
"IsOptionalPhase": false
},
{
"Name": "Staging",
"AutomaticDeploymentTargets": ["Environments-105"],
"OptionalDeploymentTargets": [],
"MinimumEnvironmentsBeforePromotion": 0,
"IsOptionalPhase": false
}
]
}'
```
### Create Docker Feed (GHCR)
```bash
curl -s -H "X-Octopus-ApiKey: $API_KEY" \
-H "Content-Type: application/json" \
-X POST "https://taniwha.octopus.app/api/$SPACE_ID/feeds" \
-d '{
"FeedType": "Docker",
"Name": "GHCR Non-Prod",
"FeedUri": "https://ghcr.io"
}'
```
### Create Step Template (Action Template)
```bash
curl -s -H "X-Octopus-ApiKey: $API_KEY" \
-H "Content-Type: application/json" \
-X POST "https://taniwha.octopus.app/api/$SPACE_ID/actiontemplates" \
-d '{
"Name": "Run Unit Tests",
"Description": "Language-specific unit test suite",
"ActionType": "Octopus.Script",
"Properties": {
"Octopus.Action.Script.ScriptSource": "Inline",
"Octopus.Action.Script.Syntax": "PowerShell",
"Octopus.Action.Script.ScriptBody": "Write-Host \"Running tests...\""
},
"Parameters": [
{
"Name": "Language",
"Label": "Programming Language",
"DefaultValue": "go",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
}
]
}'
```
### Create Release via API (CI-driven)
```bash
curl -s -X POST \
-H "X-Octopus-ApiKey: $API_KEY" \
-H "Content-Type: application/json" \
"https://taniwha.octopus.app/api/$SPACE_ID/releases" \
-d '{
"ProjectId": "Projects-XXX",
"ChannelId": "Channels-XXX",
"Version": "1.2.3+202603251530",
"SelectedPackages": [{
"ActionName": "Deploy Non-Prod Image",
"PackageReferenceName": "service-image",
"Version": "1.2.3+202603251530"
}]
}'
```
## Idempotent Script Pattern
For automation scripts that may be re-run:
```bash
# Check if resource exists before creating
existing=$(curl -s -H "X-Octopus-ApiKey: $API_KEY" \
"https://taniwha.octopus.app/api/$SPACE_ID/projectgroups?take=100" \
| python3 -c "
import sys, json
name = sys.argv[1]
for item in json.load(sys.stdin).get('Items', []):
if item['Name'] == name:
print(item['Id'])
break
" "Marketplace" 2>/dev/null || echo "")
if [[ -n "$existing" ]]; then
echo "Already exists: $existing"
else
# Create it
curl -s -X POST ...
fi
```
## References
- [Octopus REST API](https://octopus.com/docs/octopus-rest-api)
- [API Examples (GitHub)](https://github.com/OctopusDeploy/OctopusDeploy-Api)

119
platformhub/architecture.md Normal file
View File

@@ -0,0 +1,119 @@
# Platform Hub Architecture
## What Is Platform Hub?
Platform Hub is Octopus Deploy's mechanism for creating reusable deployment process templates that can be shared across spaces. It enables platform engineering teams to define standard deployment pipelines that project teams consume.
## Key Concepts
### The Three Layers
```
┌─────────────────────────────────────────────────────────────┐
│ Platform Hub Git Repo │
│ (e.g., github.com/org/taniwha.platform_hub) │
│ │
│ .octopus/process-templates/ │
│ ├── standard-go-service-deploy.ocl │
│ ├── python-ml-service-deploy.ocl │
│ ├── payment-service-deploy.ocl │
│ └── ... │
│ │
│ Defines: steps, parameters, scripts │
│ Stored in: Git (OCL files) │
└──────────────────────────┬──────────────────────────────────┘
│ Octopus reads OCL from Git
┌─────────────────────────────────────────────────────────────┐
│ Platform Hub (Octopus Instance) │
│ │
│ Publishing & Sharing: │
│ - Version management (semantic versioning) │
│ - Space visibility (which spaces can use each template) │
│ - Stored in: Octopus database (NOT Git) │
└──────────────────────────┬──────────────────────────────────┘
│ Projects reference templates
┌─────────────────────────────────────────────────────────────┐
│ Project (in any shared space) │
│ │
│ deployment_process.ocl: │
│ process_template "deploy-my-app" { │
│ process_template_slug = "standard-go-service-deploy" │
│ version_mask = "1.X" │
│ parameter "cloud_target" { value = "aws" } │
│ } │
│ │
│ Stored in: Project's Git repo (if CaC) or database │
└─────────────────────────────────────────────────────────────┘
```
### What Lives Where
| Artifact | Storage | Managed By |
|----------|---------|------------|
| Process template OCL (steps, scripts, parameters) | Git repo | Engineers via commits |
| Template versioning (major.minor.patch) | Octopus database | UI (publish action) |
| Template sharing (space visibility) | Octopus database | UI only — no API/CLI |
| Step templates (ActionTemplates) | Octopus database, per-space | API or UI |
| Project consumption of templates | Project Git repo (CaC) or DB | Engineers or API |
### Step Templates vs Process Templates
These are **different things** that complement each other:
| | Step Templates | Process Templates |
|---|---|---|
| **Scope** | Single step (one action) | Multi-step pipeline |
| **Storage** | Octopus DB, per-space | Git repo (OCL) |
| **Created via** | API or UI | Git commit |
| **Referenced by** | `Octopus.Action.Template.Id` | `process_template_slug` |
| **Cross-space** | No — space-scoped | Yes — via Platform Hub sharing |
| **Use in process templates** | Cannot reference cross-space | N/A |
**Critical:** Process templates in Platform Hub **cannot reference step templates from other spaces**. If you have reusable step templates in Space A, a process template in Platform Hub cannot use them. Instead, process templates must use inline `action_type` definitions.
## Git Repo Structure
The Platform Hub repo has a fixed structure that Octopus expects:
```
.octopus/
process-templates/
template-slug-name.ocl # One file per process template
another-template.ocl
README.md # Optional documentation
```
- Files must be in `.octopus/process-templates/`
- File extension must be `.ocl`
- The filename becomes the template slug (minus `.ocl`)
- Octopus reads from the `main` branch (configurable)
## Versioning and Updates
- Templates use **semantic versioning** (major.minor.patch)
- Publishing creates a new version
- Consuming projects use `version_mask` to control updates:
- `"1.X"` — auto-update on minor/patch, manual upgrade for major
- `"1.2.X"` — auto-update on patch only
- `"1.2.3"` — pinned to exact version
- **Major version bumps** are breaking changes: parameter renames, step removals
- **Minor/patch** for non-breaking: new optional params, script improvements, bug fixes
## Setting Up a New Platform Hub
1. Create a Git repo (GitHub, Gitea, etc.)
2. Create `.octopus/process-templates/` directory
3. Add OCL files (see [OCL Syntax Reference](ocl-syntax.md))
4. In Octopus: configure Platform Hub to point at the Git repo
5. Templates appear in the UI after Octopus reads the repo
6. Publish each template (UI) to create a version
7. Share each template with desired spaces (UI)
## References
- [Process Templates Docs](https://octopus.com/docs/platform-hub/templates/process-templates)
- [Template Parameters](https://octopus.com/docs/platform-hub/templates/parameters)
- [Publishing & Sharing](https://octopus.com/docs/platform-hub/templates/publishing-and-sharing)
- [Best Practices](https://octopus.com/docs/platform-hub/templates/process-templates/best-practices)

160
platformhub/gotchas.md Normal file
View File

@@ -0,0 +1,160 @@
# Platform Hub Gotchas and Troubleshooting
Every error encountered while building the PlatformHub-Demo project, and how to fix it.
## OCL Parse Errors
### "Action Template with ID 'ActionTemplates-XX' and version v0 specified in OCL was not found"
**Cause:** Process template references a step template (ActionTemplate) by ID, but step templates are space-scoped. Platform Hub operates at instance level and can't see step templates in individual spaces.
**Fix:** Don't reference step templates in process template OCL. Use inline `action_type` definitions instead:
```hcl
# WRONG — cross-space reference
action {
properties = {
Octopus.Action.Template.Id = "ActionTemplates-64"
Octopus.Action.Template.Version = "0"
}
}
# RIGHT — inline action
action {
action_type = "Octopus.Script"
properties = {
Octopus.Action.RunOnServer = "true"
Octopus.Action.Script.ScriptSource = "Inline"
Octopus.Action.Script.Syntax = "PowerShell"
Octopus.Action.Script.ScriptBody = <<-EOT
Write-Host "Inline script here"
EOT
OctopusUseBundledTooling = "False"
}
worker_pool_variable = "worker_pool"
}
```
### "A step must specify a worker pool parameter"
**Cause:** Every step in a process template must have a worker pool, either directly or via a variable. The template itself must define a `WorkerPool` parameter.
**Fix:** Add a `worker_pool` parameter to the template and reference it from every action:
```hcl
# Add this parameter to the template
parameter "worker_pool" {
display_settings = {
Octopus.ControlType = "WorkerPool"
}
help_text = "Worker pool for server-side steps"
label = "Worker Pool"
}
# On EVERY action (both RunOnServer=true and RunOnServer=false):
action {
action_type = "Octopus.Script"
properties = { ... }
worker_pool_variable = "worker_pool" # Must reference the parameter
}
```
Note: `worker_pool_variable = ""` (empty string) will NOT work. It must reference an actual parameter name.
### "Name value contains invalid characters"
**Cause:** Template or step names contain characters outside the allowed set.
**Allowed:** Letters, numbers, periods, commas, dashes, underscores, hashes
**Not allowed:** Parentheses `()`, slashes `/`, ampersands `&`, colons `:`, at-signs `@`
```
# WRONG
name = "Run Security Scan (SAST/SCA)"
# RIGHT
name = "Run Security Scan - SAST and SCA"
```
## API and Scripting Issues
### Step template names created as numbers instead of text
**Cause:** The bash variable `GROUPS` is pre-set by bash completion scripts (contains numeric group IDs). Assigning to `GROUPS` in a script that sources other files will silently use the pre-existing value.
**Fix:** Use a unique variable name that won't collide with shell builtins or completion scripts:
```bash
# WRONG — GROUPS may already be set by bash completion
GROUPS=("Marketplace" "Payments" "Orders")
# RIGHT — use a unique name
PROJECT_GROUPS=("Marketplace" "Payments" "Orders")
```
### Action template (step template) creation: HTTP 400 with name errors
**Cause:** Same name restriction as process templates. The API enforces the same character rules.
### Octopus API POST with nested command substitution loses values
**Cause:** Nested `$(...)` in bash can mangle variable expansion. Avoid constructing JSON inside `$(octopus_post "/endpoint" "$(python3 ...)")`.
**Fix:** Build the JSON body in a separate variable first:
```bash
# WRONG — nested substitution
response=$(octopus_post "/projectgroups" "$(python3 -c "..." "$name")")
# RIGHT — build body first
body="{\"Name\": \"$name\"}"
response=$(octopus_post "/projectgroups" "$body")
```
## Publishing and Sharing
### Templates visible in Platform Hub but not in project spaces
**Cause:** Templates must be explicitly published (versioned) and shared with target spaces. Both operations are UI-only — there is no API or CLI for this.
**Fix:** For each template:
1. Go to Platform Hub in the Octopus UI
2. Click the template → Publish (creates a version)
3. Click Share → select target spaces → Save
### Template changes not reflected in consuming projects
**Cause:** Template versioning. Changes in Git are picked up by Platform Hub but won't affect projects until a new version is published. Projects with `version_mask = "1.X"` will auto-update on minor/patch publications.
## OCL Syntax Specifics
### Heredoc for multi-line scripts
PowerShell scripts with double quotes need heredoc syntax:
```hcl
Octopus.Action.Script.ScriptBody = <<-EOT
$name = $OctopusParameters['Octopus.Project.Name']
Write-Host "Deploying $name"
EOT
```
The `<<-EOT` variant (with dash) allows the closing `EOT` to be indented. Without the dash, `EOT` must be at column 0.
### Parameter references: single vs double braces
- `#{param_name}` — standard Octopus variable substitution (most properties)
- `#{{param_name}}` — escaped substitution (used in some properties like `GitRepository.FilePathFilters`)
### PowerShell variable access in scripts
Inside script bodies, use `$OctopusParameters['Variable.Name']`, not `#{Variable.Name}`:
```powershell
# In script body:
$project = $OctopusParameters['Octopus.Project.Name']
$cloud = $OctopusParameters['cloud_target']
# NOT this (only works in OCL properties, not script text):
# #{Octopus.Project.Name}
```

276
platformhub/ocl-syntax.md Normal file
View File

@@ -0,0 +1,276 @@
# OCL Syntax Reference for Process Templates
## Grammar Rules
OCL (Octopus Configuration Language) follows a strict format. The EBNF grammar is defined at https://github.com/OctopusDeploy/Ocl.
### Core Rules
- **Name, `=`, and value** must be on the same line
- **Block name, labels, and `{`** must be on the same line
- **Closing `}`** must be on its own line (except empty blocks like `value "default" {}`)
- **Strings** use double quotes, cannot contain unescaped `"`
- **Multi-line strings** use heredoc: `<<-EOT` / `EOT`
- **Arrays** use `["item1", "item2"]`
- **Dictionaries** use `{ key = "value" }` (one entry per line inside braces)
### Name Restrictions
Template and step names can only contain: letters, numbers, periods, commas, dashes, underscores, hashes.
**Invalid:** `Run Security Scan (SAST/SCA)` — parentheses and slashes not allowed
**Valid:** `Run Security Scan - SAST and SCA`
## Process Template File Structure
```hcl
name = "Template Display Name"
description = "What this template does"
# Parameters (consumed by projects, referenced in steps)
parameter "param_name" {
display_settings = {
Octopus.ControlType = "SingleLineText"
}
help_text = "Description for UI"
label = "Display Label"
value "default_value" {} # Optional default
}
# Worker pool parameter (REQUIRED — every template needs this)
parameter "worker_pool" {
display_settings = {
Octopus.ControlType = "WorkerPool"
}
help_text = "Worker pool for server-side steps"
label = "Worker Pool"
}
# Steps (executed in order)
step "step-slug" {
name = "Step Display Name"
start_trigger = "StartAfterPrevious" # or "StartWithPrevious"
action {
action_type = "Octopus.Script"
properties = {
Octopus.Action.RunOnServer = "true"
Octopus.Action.Script.ScriptSource = "Inline"
Octopus.Action.Script.Syntax = "PowerShell"
Octopus.Action.Script.ScriptBody = <<-EOT
Write-Host "Hello from #{Octopus.Project.Name}"
EOT
OctopusUseBundledTooling = "False"
}
worker_pool_variable = "worker_pool"
}
}
```
## Parameter Types
| Type | `Octopus.ControlType` | Can Default | Notes |
|------|----------------------|-------------|-------|
| Single-line text | `SingleLineText` | Yes | Most common for string values |
| Multi-line text | `MultiLineText` | Yes | For scripts, YAML, JSON |
| Sensitive | `Sensitive` | Yes | Encrypted in DB |
| Checkbox | `Checkbox` | Yes | Boolean |
| Dropdown | `Select` | Yes | Predefined options |
| Target Tags | `TargetTags` | No | For Kubernetes/deployment targets |
| Worker Pool | `WorkerPool` | No | **Required on every template** |
| Package | (package) | No | Container image references |
| Environments | (environments) | No | |
| Channels | (channels) | No | |
### Default Values
```hcl
# String default
parameter "cloud_target" {
display_settings = { Octopus.ControlType = "SingleLineText" }
help_text = "Cloud provider"
label = "Cloud Target"
value "gcp" {} # Default value in empty block
}
# No default (must be set by consuming project)
parameter "target_tags" {
display_settings = { Octopus.ControlType = "TargetTags" }
help_text = "K8s target tags"
label = "Target Tags"
}
```
## Step Structure
### Inline Script Step (most common in process templates)
```hcl
step "step-slug" {
name = "Display Name"
start_trigger = "StartAfterPrevious"
action {
action_type = "Octopus.Script"
properties = {
Octopus.Action.RunOnServer = "true"
Octopus.Action.Script.ScriptSource = "Inline"
Octopus.Action.Script.Syntax = "PowerShell" # or "Bash"
Octopus.Action.Script.ScriptBody = <<-EOT
# PowerShell script here
$project = $OctopusParameters['Octopus.Project.Name']
Write-Host "Deploying $project"
EOT
OctopusUseBundledTooling = "False"
}
worker_pool_variable = "worker_pool"
}
}
```
### Deployment Target Step (runs on targets, not server)
```hcl
step "deploy-step" {
name = "Deploy to K8s"
start_trigger = "StartAfterPrevious"
properties = {
Octopus.Action.TargetRoles = "#{target_tags}" # References parameter
}
action {
action_type = "Octopus.Script"
properties = {
Octopus.Action.RunOnServer = "false" # Runs on target
Octopus.Action.Script.ScriptSource = "Inline"
Octopus.Action.Script.Syntax = "PowerShell"
Octopus.Action.Script.ScriptBody = <<-EOT
Write-Host "Deploying to target"
EOT
OctopusUseBundledTooling = "False"
}
worker_pool_variable = "worker_pool"
}
}
```
### Kubernetes Raw YAML Step
```hcl
step "k8s-deploy" {
name = "Apply Kubernetes YAML"
properties = {
Octopus.Action.TargetRoles = "#{target_tags}"
}
action {
action_type = "Octopus.KubernetesDeployRawYaml"
properties = {
Octopus.Action.GitRepository.FilePathFilters = "#{{yaml_path}}"
Octopus.Action.GitRepository.Source = "External"
Octopus.Action.Kubernetes.DeploymentTimeout = "180"
Octopus.Action.Kubernetes.ResourceStatusCheck = "True"
Octopus.Action.Kubernetes.ServerSideApply.Enabled = "True"
Octopus.Action.Kubernetes.ServerSideApply.ForceConflicts = "True"
Octopus.Action.KubernetesContainers.Namespace = "#{namespace}"
Octopus.Action.Script.ScriptSource = "GitRepository"
}
worker_pool_variable = "worker_pool"
git_dependencies {
default_branch = "main"
file_path_filters = ["#{yaml_path}"]
git_credential_type = "Anonymous"
repository_uri = "#{repo_url}"
}
}
}
```
## Referencing Variables
### Octopus System Variables
Use `$OctopusParameters['Variable.Name']` in PowerShell scripts:
```powershell
$project = $OctopusParameters['Octopus.Project.Name']
$release = $OctopusParameters['Octopus.Release.Number']
$env = $OctopusParameters['Octopus.Environment.Name']
$channel = $OctopusParameters['Octopus.Release.Channel.Name']
```
### Template Parameters
In OCL properties (outside scripts): `#{parameter_name}`
In PowerShell scripts: `$OctopusParameters['parameter_name']`
```hcl
# In OCL properties
Octopus.Action.TargetRoles = "#{target_tags}"
# In script body
$cloudTarget = $OctopusParameters['cloud_target']
```
**Double-bracing escape:** In some OCL properties, use `#{{param}}` to escape Octopus variable substitution:
```hcl
Octopus.Action.GitRepository.FilePathFilters = "#{{yaml_path}}"
```
### Output Variables
Set output variables from scripts for use in later steps:
```powershell
Write-Host "##octopus[setVariable name='CoveragePercent' value='87']"
```
Read in subsequent steps:
```powershell
$coverage = $OctopusParameters['Octopus.Action[run-unit-tests].Output.CoveragePercent']
```
## Channel Scoping
Scope steps to specific channels (for dual-image patterns):
```hcl
action {
action_type = "Octopus.Script"
channels = ["non-prod"] # Only runs in this channel
properties = { ... }
}
```
## Environment Scoping
```hcl
action {
environments = ["production"] # Only in prod
excluded_environments = ["development"] # Not in dev
}
```
## Step Properties Reference
| Property | Type | Values | Default |
|---|---|---|---|
| `step.condition` | enum | `Success`, `Failure`, `Always`, `Variable` | `Success` |
| `step.start_trigger` | enum | `StartAfterPrevious`, `StartWithPrevious` | `StartAfterPrevious` |
| `step.package_requirement` | enum | `LetOctopusDecide`, `BeforePackageAcquisition`, `AfterPackageAcquisition` | `LetOctopusDecide` |
| `action.channels` | string[] | channel slugs | all |
| `action.environments` | string[] | environment slugs | all |
| `action.excluded_environments` | string[] | environment slugs | none |
| `action.is_disabled` | bool | | `False` |
| `action.is_required` | bool | | `False` |
| `action.notes` | string | step description | |
| `action.worker_pool` | string | worker pool slug | |
| `action.worker_pool_variable` | string | variable name | |
## References
- [OCL Format Specification](https://octopus.com/docs/projects/version-control/ocl-file-format)
- [Config as Code Reference](https://octopus.com/docs/projects/version-control/config-as-code-reference)
- [OCL Grammar (EBNF)](https://github.com/OctopusDeploy/Ocl)

View File

@@ -0,0 +1,138 @@
# Process Template Patterns
Proven patterns for different deployment types, extracted from the PlatformHub-Demo project (30 microservices, 3 clouds, 8 teams).
## Design Principles
1. **One template per deployment pattern**, not per cloud or per service. Use parameters to vary behaviour.
2. **Parameters for everything that varies** between consuming projects: cloud target, language, database type, target tags.
3. **Sensible defaults** on parameters to reduce friction — consuming projects only override what differs.
4. **Every template needs a `worker_pool` parameter** (type `WorkerPool`) — this is mandatory.
5. **Inline scripts, not step template references** — process templates can't see step templates in other spaces.
## Template Catalogue
### Standard Go Service Deploy
**Use for:** Go microservices without special compliance or database requirements.
**Steps:** Unit tests → Security scan → Container image scan → Helm deploy → Monitoring
**Parameters:** `target_tags`, `cloud_target` (default: gcp), `worker_pool`
**Services example:** listing-service, search-service, category-service, config-service, order-service
Key characteristics:
- Go test output with race detection and coverage
- Semgrep SAST + Trivy SCA
- Distroless base image scan + SBOM generation
- Helm upgrade with cluster mapping by cloud target
- Prometheus ServiceMonitor + Grafana dashboard + SLO alerting
### Python ML Service Deploy
**Use for:** Python services, especially ML/data pipeline services with model dependencies.
**Steps:** Unit tests → Integration tests → Security scan → Container image scan → Helm deploy → Monitoring
**Parameters:** `target_tags`, `cloud_target` (default: gcp), `worker_pool`
**Services example:** recommendation-service, fraud-service, moderation-service, ml-platform, analytics-pipeline
Key characteristics:
- pytest with coverage table
- Docker-compose integration tests (model validation, data pipeline tests)
- Python-specific SAST (Semgrep + Bandit) + SCA (Safety + pip-audit)
- GPU resource requests in Helm deploy
- ML-specific monitoring: inference latency, model drift, batch queue depth
### Payment Service Deploy
**Use for:** Payment-path services requiring PCI-DSS compliance and zero-downtime deployment.
**Steps:** Unit tests → Security scan → Container image scan → PCI-DSS check → Blue-green deploy → Monitoring → Rollback check
**Parameters:** `target_tags`, `cloud_target` (default: aws), `worker_pool`
**Services example:** payment-gateway, wallet-service, ledger-service, payout-service, escrow-service
Key characteristics:
- Enhanced security scan with Gitleaks secret detection
- 6-check PCI-DSS compliance gate (image signature, SBOM, secrets, TLS, network policy, audit logging)
- Blue-green deployment with canary traffic phases (10% → 100%)
- 4-nines SLO (99.99%), payment-specific alerting (circuit breaker, refund rate)
- Post-deploy health validation with automatic rollback decision
### Database Service Deploy
**Use for:** Services with database dependencies requiring schema migrations.
**Steps:** Unit tests → Security scan → Database migration → Container image scan → Helm deploy → Monitoring
**Parameters:** `target_tags`, `cloud_target` (default: gcp), `database_type` (default: postgres), `language` (default: go), `worker_pool`
**Services example:** user-service, ledger-service, order-service (any service with a DB)
Key characteristics:
- Language-aware unit tests (Go/Python/Node switch)
- SQL injection-focused security rules
- Pre-migration snapshot with cloud-appropriate tooling (pg_dump, mysqldump, mongodump)
- Versioned migration with per-migration timing
- Post-migration validation (schema version, constraint check, data integrity)
- DB-specific monitoring: connection pool, slow queries, migration version mismatch
### Node.js Service Deploy
**Use for:** Node.js services including API gateways, messaging, and notification services.
**Steps:** Unit tests → Security scan → Container image scan → Helm deploy → Feature flag seeding → Monitoring
**Parameters:** `target_tags`, `cloud_target` (default: azure), `worker_pool`
**Services example:** messaging-service, notification-service, api-gateway
Key characteristics:
- Jest-style test output with coverage table
- npm audit + Trivy SCA
- Feature flag seeding with environment-aware rollout percentages
- Cloud-specific secrets manager integration (Azure Key Vault / AWS SM / GCP SM)
- Node.js-specific monitoring: event loop lag, heap usage, WebSocket connections
## How Projects Consume Templates
In a project's `deployment_process.ocl`:
```hcl
process_template "deploy-listing-service" {
name = "Deploy Listing Service"
process_template_slug = "standard-go-service-deploy"
version_mask = "1.X" # Auto-update minor/patch
parameter "target_tags" {
value = "gke-marketplace"
}
parameter "cloud_target" {
value = "gcp"
}
parameter "worker_pool" {
value = "WorkerPools-1"
}
}
```
## Choosing the Right Template
```
Does the service handle payments or financial data?
└── YES → Payment Service Deploy
Does the service have database migrations?
└── YES → Database Service Deploy
Is the service Python-based (ML, data, analytics)?
└── YES → Python ML Service Deploy
Is the service Node.js-based?
└── YES → Node.js Service Deploy
Default → Standard Go Service Deploy
```
## Template-to-Service Mapping (PlatformHub-Demo)
| Template | Services |
|----------|----------|
| Standard Go Service | listing, search, search-indexer, category, media, config, event-bus, shipping, observability-collector, reporting, review, dispute |
| Python ML Service | recommendation, fraud, moderation, ml-platform, analytics-pipeline |
| Payment Service | payment-gateway, wallet, ledger, payout, escrow, kyc |
| Database Service | user, auth, user-activity, order (overlay with others) |
| Node.js Service | messaging, notification, api-gateway |
Note: Some services (like `order-service`) could use either Standard Go or Database Service depending on whether DB migrations are part of the deployment process.