Automation & Scripting
JSON templates, jq pipelines, idempotent scripts, bulk operations, the apply command, and GitHub Actions workflows for Megaport CLI automation
Prerequisites
- Megaport CLI installed and configured
- Basic shell scripting (bash)
- jq installed
The Megaport CLI is designed for automation. JSON input mode, structured JSON/CSV output, and consistent exit codes make it composable with shell scripts, CI/CD pipelines, and infrastructure-as-code tooling.
JSON template pattern
Store resource configurations as JSON files in version control. Use environment variables for values that differ between environments.
templates/port-template.json:
{
"name": "${PORT_NAME}",
"locationId": ${LOCATION_ID},
"portSpeed": ${PORT_SPEED},
"term": 12,
"marketPlaceVisibility": false,
"costCentre": "${ENVIRONMENT}"
}
Render and apply:
export PORT_NAME="Sydney Primary"
export LOCATION_ID=3
export PORT_SPEED=10000
export ENVIRONMENT=production
envsubst < templates/port-template.json > /tmp/port-config.json
megaport-cli ports buy --json-file /tmp/port-config.json
For more complex templating (conditionals, loops), use jq to transform a base template:
# Inject a dynamic value into a fixed template
jq --arg name "Sydney Primary" '.name = $name' base-port.json > port.json
megaport-cli ports buy --json-file port.json
Declarative provisioning with apply
The apply command provisions multiple resources from a single YAML or JSON config file — the closest the CLI gets to a built-in IaC primitive. Resources are created in dependency order (Ports → MCRs → MVEs → VXCs), and VXC endpoints can reference other resources in the same file using {{.type.name}} template syntax.
infrastructure.yaml:
ports:
- name: Sydney Primary
location_id: 3
speed: 10000
term: 12
marketplace_visibility: false
cost_centre: AU-NET-001
resource_tags:
env: production
mcrs:
- name: Cloud Router SYD
location_id: 3
speed: 5000
term: 12
asn: 64512
vxcs:
- name: Sydney to Cloud Router
rate_limit: 1000
term: 12
a_end:
product_uid: "{{.port.Sydney Primary}}"
vlan: 100
b_end:
product_uid: "{{.mcr.Cloud Router SYD}}"
vlan: 100
Apply it:
# Validate without provisioning
megaport-cli apply -f infrastructure.yaml --dry-run
# Provision (with confirmation prompt)
megaport-cli apply -f infrastructure.yaml
# Non-interactive for CI/CD
megaport-cli apply -f infrastructure.yaml --yes
# Roll back every resource created in this run if any step fails
megaport-cli apply -f infrastructure.yaml --yes --rollback-on-failure
# JSON output for parsing the result table
megaport-cli apply -f infrastructure.yaml --output json
The {{.port.<name>}}, {{.mcr.<name>}}, and {{.mve.<name>}} template references resolve to UIDs of resources defined earlier in the same file — so you can describe a complete network in one document without manual UID copy-paste.
Use --dry-run in CI
Run apply -f infrastructure.yaml --dry-run as a PR check. It validates the entire config without provisioning anything — you catch schema and dependency errors before merging.
`--rollback-on-failure` — all-or-nothing applies
By default, if apply fails partway through, every resource it had already created stays around — you need to clean them up manually. Adding --rollback-on-failure flips that behaviour: on the first failure, every resource provisioned during the run is deleted, and the command exits with the failure plus a list of any orphans it couldn't reverse. Use it in CI for atomic deploys.
Apply does not provision cloud VXCs
The apply VXC schema only supports port-to-port, port-to-MCR, and port-to-MVE links — partner configs (AWS, Azure, Google, Oracle, IBM, Transit, vRouter) are not supported. For cloud connectivity, build the underlying ports/MCRs/MVEs with apply, then attach cloud VXCs with vxc buy --json-file against the partner port UID. See the full schema and limits in the Apply reference.
Export existing resources as templates
The --export flag on any get command outputs a recreatable JSON config — ready to use with buy --json. This is a fast way to clone resources or build templates from existing infrastructure.
# Export an existing port's config
megaport-cli ports get <PORT-UID> --export > port-template.json
# Modify and create a new port from the template
jq '.name = "Sydney Secondary"' port-template.json > new-port.json
megaport-cli ports buy --json-file new-port.json
Works with all resource types:
megaport-cli mcr get <MCR-UID> --export > mcr-template.json
megaport-cli mve get <MVE-UID> --export > mve-template.json
Scripting flags
Two flags make buy commands script-friendly:
--yes/-y— skip the confirmation prompt (no interactive "are you sure?" question)--no-wait— return immediately after submitting the order instead of waiting for provisioning to complete
# Non-interactive provisioning for CI/CD
megaport-cli ports buy --json-file port.json --yes --no-wait
Chain operations with jq
Parse JSON output from one command and feed it into the next.
# Create a port, then look up its UID to use in subsequent commands
megaport-cli ports buy --json-file port.json
PORT_UID=$(megaport-cli ports list --output json | jq -r '.[] | select(.name == "Sydney Primary") | .uid')
echo "Port created: $PORT_UID"
AWS_PARTNER=$(megaport-cli partners list --company-name "Amazon Web Services" --location-id 3 --output json | jq -r '.[0].productUid')
megaport-cli vxc buy \
--name "Sydney to AWS" \
--a-end-uid "$PORT_UID" \
--b-end-uid "$AWS_PARTNER" \
--a-end-vlan 100 \
--rate-limit 1000 \
--term 12 \
--b-end-partner-config '{"connectType":"AWS","ownerAccount":"123456789012","type":"private","asn":65000}'
Extract specific fields:
# Get all LIVE port UIDs
megaport-cli ports list --output json | jq -r '.[] | select(.status == "LIVE") | .uid'
# Get port names and speeds as a table
megaport-cli ports list --output json | jq -r '.[] | [.name, (.speed | tostring)] | @tsv'
# Count resources by status
megaport-cli ports list --output json | jq 'group_by(.status) | map({status: .[0].status, count: length})'
Idempotency — check before creating
Avoid creating duplicate resources by checking if they already exist:
check_or_create_port() {
local name="$1"
local config_file="$2"
EXISTING=$(megaport-cli ports list --output json | \
jq -r --arg name "$name" '.[] | select(.name == $name) | .uid')
if [ -n "$EXISTING" ]; then
echo "Port '$name' already exists: $EXISTING"
echo "$EXISTING"
else
echo "Creating port '$name'..."
megaport-cli ports buy --json-file "$config_file"
megaport-cli ports list --output json | \
jq -r --arg name "$name" '.[] | select(.name == $name) | .uid'
fi
}
PORT_UID=$(check_or_create_port "Sydney Primary" port.json)
Error handling
#!/bin/bash
set -euo pipefail
# set -e → exit on error
# set -u → exit on undefined variable
# set -o pipefail → catch failures in pipes
# Validate prerequisites
command -v jq >/dev/null 2>&1 || { echo "jq is required but not installed" >&2; exit 1; }
command -v megaport-cli >/dev/null 2>&1 || { echo "megaport-cli is required but not installed" >&2; exit 1; }
# Trap errors for cleanup
cleanup() {
echo "Script failed — check resources for partial provisioning" >&2
}
trap cleanup ERR
# Test credentials before starting
megaport-cli locations list --output json > /dev/null || {
echo "Authentication failed — check MEGAPORT_ACCESS_KEY and MEGAPORT_SECRET_KEY" >&2
exit 1
}
Bulk operations
Tag all LIVE ports
megaport-cli ports list --output json | \
jq -r '.[] | select(.status == "LIVE") | .uid' | \
while IFS= read -r uid; do
echo "Tagging port: $uid"
megaport-cli ports update-tags "$uid" \
--json '{"env":"production","managed-by":"automation"}'
done
Bulk update cost centres
# Apply cost centre to all ports matching a name pattern
megaport-cli ports list --output json | \
jq -r '.[] | select(.name | startswith("SYD")) | .uid' | \
while IFS= read -r uid; do
megaport-cli ports update "$uid" --cost-centre "AU-INFRA-001"
done
Export all resources to CSV report
#!/bin/bash
DATE=$(date +%Y-%m-%d)
REPORT="megaport-report-${DATE}"
megaport-cli ports list --output csv > "${REPORT}-ports.csv"
megaport-cli mcr list --output csv > "${REPORT}-mcrs.csv"
megaport-cli mve list --output csv > "${REPORT}-mves.csv"
megaport-cli vxc list --output csv > "${REPORT}-vxcs.csv"
echo "Reports generated:"
ls -lh "${REPORT}"*.csv
Health checks and monitoring
# Find any non-LIVE resources (potential issues)
echo "=== Non-LIVE ports ==="
megaport-cli ports list --output json | \
jq '.[] | select(.status != "LIVE") | {name, status, uid}'
echo "=== Non-LIVE VXCs ==="
megaport-cli vxc list --output json | \
jq '.[] | select(.status != "LIVE") | {name, status, uid}'
# Count resources by type
echo "Ports: $(megaport-cli ports list --output json | jq length)"
echo "VXCs: $(megaport-cli vxc list --output json | jq length)"
echo "MCRs: $(megaport-cli mcr list --output json | jq length)"
GitHub Actions workflow
Automate provisioning on push to main. Secrets are injected as environment variables — credentials never touch the codebase.
.github/workflows/provision-network.yml:
name: Provision Megaport Network
on:
push:
branches: [main]
paths:
- 'infrastructure/megaport/**'
workflow_dispatch:
jobs:
provision:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Install Megaport CLI
run: go install github.com/megaport/megaport-cli@latest
- name: Verify credentials
env:
MEGAPORT_ACCESS_KEY: ${{ secrets.MEGAPORT_ACCESS_KEY }}
MEGAPORT_SECRET_KEY: ${{ secrets.MEGAPORT_SECRET_KEY }}
MEGAPORT_ENVIRONMENT: production
run: megaport-cli locations list --output json > /dev/null
- name: Provision infrastructure
env:
MEGAPORT_ACCESS_KEY: ${{ secrets.MEGAPORT_ACCESS_KEY }}
MEGAPORT_SECRET_KEY: ${{ secrets.MEGAPORT_SECRET_KEY }}
MEGAPORT_ENVIRONMENT: production
run: ./infrastructure/megaport/provision.sh
- name: Export resource report
env:
MEGAPORT_ACCESS_KEY: ${{ secrets.MEGAPORT_ACCESS_KEY }}
MEGAPORT_SECRET_KEY: ${{ secrets.MEGAPORT_SECRET_KEY }}
MEGAPORT_ENVIRONMENT: production
run: |
megaport-cli ports list --output json | jq '.' > artifacts/ports.json
megaport-cli vxc list --output json | jq '.' > artifacts/vxcs.json
- uses: actions/upload-artifact@v4
with:
name: megaport-state
path: artifacts/
Store credentials as GitHub Secrets
Add MEGAPORT_ACCESS_KEY and MEGAPORT_SECRET_KEY under Settings → Secrets and variables → Actions in your repository. Never put credentials in workflow files or commit them to the repo.
Team config management
Onboard new team members and share environment configurations without sharing credentials.
# Export current config — credentials appear as [REDACTED]
megaport-cli config export --file team-config-template.json
# Commit team-config-template.json to your repo
# New team member: import the template, then fill in their credentials
megaport-cli config import --file team-config-template.json
megaport-cli config update-profile production \
--access-key their_access_key \
--secret-key their_secret_key
# Verify
megaport-cli config view
Standardise output format across the team:
# Set in team config template before exporting
megaport-cli config set-default output json
What's next?
- Multi-Cloud Connectivity — a complete automation script building a three-cloud architecture
- Port Lifecycle — the operations you'll automate most often
- Config Profiles — managing profiles for multiple environments