Skip to content
Intermediate - Solutions Architect 40 minutes

Automation & Scripting

JSON templates, jq pipelines, idempotent scripts, bulk operations, 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:

json
{
  "name": "${PORT_NAME}",
  "locationId": ${LOCATION_ID},
  "portSpeed": ${PORT_SPEED},
  "term": 12,
  "marketPlaceVisibility": false,
  "costCentre": "${ENVIRONMENT}"
}

Render and apply:

bash
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:

bash
# 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

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.

bash
# 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:

bash
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
bash
# 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.

bash
# 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"

megaport-cli vxc buy \
  --name "Sydney to AWS" \
  --a-end-uid "$PORT_UID" \
  --a-end-vlan 100 \
  --rate-limit 1000 \
  --term 12 \
  --b-end-partner-config '{"connectType":"AWS","ownerAccount":"123456789012","type":"private"}'

Extract specific fields:

bash
# 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:

bash
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

bash
#!/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

bash
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

bash
# 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

bash
#!/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

bash
# 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:

yaml
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.

bash
# 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:

bash
# Set in team config template before exporting
megaport-cli config set-default output json

What's next?