Skip to main content

Examples

Working examples for the most common workflows. Each script is self-contained, uses only bash, curl, and jq, and is ready to copy and run after setting two environment variables.

Setup

export WSI_EMAIL="you@yourcompany.com"
export WSI_PASSWORD="your-password"

All examples share this helper at the top:

#!/bin/bash
set -euo pipefail

API="https://portal.webberstop.com/backend/api"

TOKEN=$(curl -s "$API/login" \
-H "Content-Type: application/json" \
-d "{\"email\":\"$WSI_EMAIL\",\"password\":\"$WSI_PASSWORD\"}" \
| jq -r '.token')

api() {
local method=$1 path=$2
shift 2
curl -sS -X "$method" "$API$path" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
"$@"
}

Example 1: Provision a complete VPC stack

This script creates a VPC, a network tier, an ACL with common rules, a VM in the tier, a public IP, and a port-forward rule for HTTPS.

#!/bin/bash
set -euo pipefail
# (paste helper from Setup above)

# Resolve IDs from names
ZONE_ID=$(api GET "/zones" | jq -r '.zones[] | select(.name=="Noida01") | .id')
VPC_OFF_ID=$(api GET "/vpc-offerings" | jq -r '.vpcOfferings[] | select(.name=="Default VPC Offering") | .id')
NET_OFF_ID=$(api GET "/network-offerings?forVpc=true" | jq -r '.networkOfferings[] | select(.name=="DefaultIsolatedNetworkOfferingForVpcNetworks") | .id')
SVC_OFF_ID=$(api GET "/service-offerings" | jq -r '.serviceOfferings[] | select(.name=="General Purpose 2vCPU 8GB") | .id')
TPL_ID=$(api GET "/templates?type=featured" | jq -r '.templates[] | select(.name=="Ubuntu 22.04 LTS") | .id')

echo "Zone: $ZONE_ID"
echo "VPC offering: $VPC_OFF_ID"
echo "Network offering: $NET_OFF_ID"
echo "Service offering: $SVC_OFF_ID"
echo "Template: $TPL_ID"

# 1. Create VPC
echo "Creating VPC..."
VPC_ID=$(api POST "/vpcs" -d "{
\"name\": \"my-prod-vpc\",
\"displayText\": \"Production VPC\",
\"cidr\": \"10.20.0.0/16\",
\"vpcOfferingId\": \"$VPC_OFF_ID\",
\"zoneId\": \"$ZONE_ID\"
}" | jq -r '.vpc.id')
echo "VPC created: $VPC_ID"

# 2. Create ACL list
echo "Creating ACL..."
ACL_ID=$(api POST "/network-acls" -d "{
\"name\": \"web-acl\",
\"description\": \"Web tier ACL\",
\"vpcId\": \"$VPC_ID\"
}" | jq -r '.networkAcl.id')

# 3. Add ACL rules
api POST "/network-acls/$ACL_ID/rules" -d '{
"protocol": "tcp",
"startPort": 443,
"endPort": 443,
"cidrList": "0.0.0.0/0",
"action": "allow",
"trafficType": "ingress",
"number": 100
}' > /dev/null

api POST "/network-acls/$ACL_ID/rules" -d '{
"protocol": "tcp",
"startPort": 22,
"endPort": 22,
"cidrList": "203.0.113.0/24",
"action": "allow",
"trafficType": "ingress",
"number": 110
}' > /dev/null

api POST "/network-acls/$ACL_ID/rules" -d '{
"protocol": "all",
"cidrList": "0.0.0.0/0",
"action": "allow",
"trafficType": "egress",
"number": 200
}' > /dev/null

# 4. Create network tier
echo "Creating tier..."
TIER_ID=$(api POST "/networks" -d "{
\"name\": \"web-tier\",
\"displayText\": \"Web tier\",
\"cidr\": \"10.20.10.0/24\",
\"gateway\": \"10.20.10.1\",
\"networkOfferingId\": \"$NET_OFF_ID\",
\"vpcId\": \"$VPC_ID\",
\"aclId\": \"$ACL_ID\",
\"zoneId\": \"$ZONE_ID\"
}" | jq -r '.network.id')
echo "Tier created: $TIER_ID"

# 5. Wait for VPC virtual router to be Running
echo "Waiting for VPC virtual router..."
for i in $(seq 1 30); do
STATE=$(api GET "/vpcs/$VPC_ID/routers" | jq -r '.routers[0].state // empty')
if [ "$STATE" = "Running" ]; then
echo "Router running"
break
fi
sleep 5
done

# 6. Deploy VM into tier
echo "Deploying VM..."
VM_ID=$(api POST "/instances" -d "{
\"name\": \"web-01\",
\"displayName\": \"web-01\",
\"serviceOfferingId\": \"$SVC_OFF_ID\",
\"templateId\": \"$TPL_ID\",
\"zoneId\": \"$ZONE_ID\",
\"networkIds\": [\"$TIER_ID\"]
}" | jq -r '.instance.id')
echo "VM deployed: $VM_ID"

# 7. Acquire public IP on the VPC
echo "Acquiring public IP..."
IP_RESPONSE=$(api POST "/public-ips" -d "{\"vpcId\": \"$VPC_ID\"}")
IP_ID=$(echo "$IP_RESPONSE" | jq -r '.publicIp.id')
IP_ADDR=$(echo "$IP_RESPONSE" | jq -r '.publicIp.ipAddress')
echo "Public IP: $IP_ADDR"

# 8. Create port forward rule
echo "Creating port forward..."
api POST "/port-forwards" -d "{
\"publicIpId\": \"$IP_ID\",
\"protocol\": \"tcp\",
\"publicPort\": 443,
\"privatePort\": 443,
\"virtualMachineId\": \"$VM_ID\",
\"networkId\": \"$TIER_ID\"
}" > /dev/null

echo ""
echo "Done. Stack provisioned:"
echo " VPC: $VPC_ID"
echo " Tier: $TIER_ID"
echo " VM: $VM_ID"
echo " Public IP: $IP_ADDR"
echo ""
echo "Once the VM finishes booting and your application is listening on 443,"
echo "you can reach it at https://$IP_ADDR"

Important notes on this script

  1. VPC virtual router wait: The poll loop at step 5 is required. The VPC virtual router takes 60 to 90 seconds to reach Running state after the first tier is created. Deploying a VM before that fails. Always wait.

  2. ACL before tier: Create the ACL list and rules before creating the tier so the tier is protected from the moment it comes up.

  3. CIDR planning: Use a /16 for the VPC and /24 for each tier. This gives you 251 usable IPs per tier and 256 possible tiers per VPC, enough for most production designs.

  4. Idempotency: This script is not idempotent. Re-running it creates duplicate resources. Wrap calls with existence checks before running in CI.

Example 2: Add a second tier for the database

Reuse the VPC from Example 1 and add a database tier with stricter ACL.

VPC_ID="<vpc-id-from-example-1>"

# Database ACL: only allow traffic from the web tier
DB_ACL_ID=$(api POST "/network-acls" -d "{
\"name\": \"db-acl\",
\"description\": \"Database tier ACL\",
\"vpcId\": \"$VPC_ID\"
}" | jq -r '.networkAcl.id')

# Allow MySQL from the web tier CIDR
api POST "/network-acls/$DB_ACL_ID/rules" -d '{
"protocol": "tcp",
"startPort": 3306,
"endPort": 3306,
"cidrList": "10.20.10.0/24",
"action": "allow",
"trafficType": "ingress",
"number": 100
}' > /dev/null

# Deny everything else
api POST "/network-acls/$DB_ACL_ID/rules" -d '{
"protocol": "all",
"cidrList": "0.0.0.0/0",
"action": "deny",
"trafficType": "ingress",
"number": 9000
}' > /dev/null

# Create the database tier
DB_TIER_ID=$(api POST "/networks" -d "{
\"name\": \"db-tier\",
\"displayText\": \"Database tier\",
\"cidr\": \"10.20.20.0/24\",
\"gateway\": \"10.20.20.1\",
\"networkOfferingId\": \"$NET_OFF_ID\",
\"vpcId\": \"$VPC_ID\",
\"aclId\": \"$DB_ACL_ID\",
\"zoneId\": \"$ZONE_ID\"
}" | jq -r '.network.id')

echo "Database tier created: $DB_TIER_ID"

The two tiers route to each other through the VPC virtual router automatically, with the ACL controlling allowed protocols. No peering, no VPN, no extra config.

Example 3: Scale an existing VM

Stop the VM, change the service offering, start it again.

VM_ID="<your-vm-id>"
NEW_SVC_OFF_ID=$(api GET "/service-offerings" | jq -r '.serviceOfferings[] | select(.name=="High Memory 4vCPU 16GB") | .id')

# Stop
api POST "/instances/$VM_ID/stop" > /dev/null

# Wait for stopped state
for i in $(seq 1 30); do
STATE=$(api GET "/instances/$VM_ID" | jq -r '.instance.state')
[ "$STATE" = "Stopped" ] && break
sleep 5
done

# Change offering
api PATCH "/instances/$VM_ID" -d "{\"serviceOfferingId\": \"$NEW_SVC_OFF_ID\"}" > /dev/null

# Start
api POST "/instances/$VM_ID/start" > /dev/null

echo "VM resized"

Example 4: Attach a block storage volume

VM_ID="<your-vm-id>"
ZONE_ID="<your-zone-id>"

# Create volume
VOL_ID=$(api POST "/volumes" -d "{
\"name\": \"data-volume-01\",
\"sizeGb\": 500,
\"diskOfferingId\": \"<your-disk-offering-id>\",
\"zoneId\": \"$ZONE_ID\"
}" | jq -r '.volume.id')

# Attach
api POST "/volumes/$VOL_ID/attach" -d "{\"virtualMachineId\": \"$VM_ID\"}" > /dev/null

echo "Volume attached: $VOL_ID"

After attach, the volume shows up as a raw block device on the VM (typically /dev/vdb on Linux). Format and mount it inside the VM as normal.

What's next