API Usage with curl¶
This guide provides practical examples for using the Nextcloud Operator API with curl commands.
Authentication¶
Option 1: Using Service Account Token (Recommended for Applications)¶
# Create a service account
kubectl create serviceaccount nextcloud-api-user -n default
# Create a role with Nextcloud permissions
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nextcloud-user
rules:
- apiGroups: ["k8s.bnerd.com"]
resources: ["nextclouds"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["k8s.bnerd.com"]
resources: ["nextclouds/status"]
verbs: ["get"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "create"]
EOF
# Bind the role to the service account
kubectl create clusterrolebinding nextcloud-api-user \
--clusterrole=nextcloud-user \
--serviceaccount=default:nextcloud-api-user
# Get the service account token
TOKEN=$(kubectl create token nextcloud-api-user -n default --duration=87600h)
# Get API server URL
API_SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
# Export for use in examples
export K8S_TOKEN="$TOKEN"
export K8S_API_SERVER="$API_SERVER"
Option 2: Using kubectl Proxy (Development/Testing)¶
# Start kubectl proxy in the background
kubectl proxy --port=8001 &
# Use localhost for API calls (no authentication needed with proxy)
export K8S_API_SERVER="http://localhost:8001"
Namespace Management¶
Create a Namespace for Tenant¶
TENANT_NAMESPACE="tenant-a"
curl -k -X POST "$K8S_API_SERVER/api/v1/namespaces" \
-H "Authorization: Bearer $K8S_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"apiVersion": "v1",
"kind": "Namespace",
"metadata": {
"name": "'$TENANT_NAMESPACE'",
"labels": {
"tenant": "tenant-a",
"managed-by": "nextcloud-operator"
}
}
}'
Nextcloud CRUD Operations¶
Create from Pool¶
curl -k -X POST "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds" \
-H "Authorization: Bearer $K8S_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"apiVersion": "k8s.bnerd.com/v1alpha1",
"kind": "Nextcloud",
"metadata": {
"name": "tenant-a-cloud",
"namespace": "'$TENANT_NAMESPACE'"
},
"spec": {
"poolSelector": {
"matchLabels": {
"profile": "basic"
}
},
"ingress": {
"host": "nc-basic.example.com"
}
}
}'
Create with Custom Configuration¶
curl -k -X POST "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds" \
-H "Authorization: Bearer $K8S_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"apiVersion": "k8s.bnerd.com/v1alpha1",
"kind": "Nextcloud",
"metadata": {
"name": "tenant-a-custom-cloud"
},
"spec": {
"poolSelector": {
"matchLabels": {
"profile": "basic"
}
},
"version": "29",
"ingress": {
"host": "custom.tenant-a.example.com",
"tls": {
"enabled": true
}
},
"database": {
"managed": true,
"type": "postgresql"
},
"redis": {
"enabled": true
}
}
}'
List All Nextcloud Resources¶
curl -k -X GET "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds" \
-H "Authorization: Bearer $K8S_TOKEN" | jq '.items[] | {
name: .metadata.name,
phase: .status.phase,
url: .status.url,
admin: .status.admin
}'
Get Status¶
NEXTCLOUD_NAME="tenant-a-cloud"
curl -k -X GET "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds/$NEXTCLOUD_NAME" \
-H "Authorization: Bearer $K8S_TOKEN" | jq '{
name: .metadata.name,
phase: .status.phase,
message: .status.message,
url: .status.url,
admin: .status.admin,
instanceRef: .status.instanceRef,
conditions: .status.conditions
}'
Get Admin Credentials¶
curl -k -X GET "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds/$NEXTCLOUD_NAME" \
-H "Authorization: Bearer $K8S_TOKEN" | jq '{
url: .status.url,
username: .status.admin.username,
password: .status.admin.password
}'
Update (Patch)¶
curl -k -X PATCH "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds/$NEXTCLOUD_NAME" \
-H "Authorization: Bearer $K8S_TOKEN" \
-H "Content-Type: application/merge-patch+json" \
-d '{
"spec": {
"ingress": {
"host": "new-hostname.tenant-a.example.com"
}
}
}'
Delete¶
curl -k -X DELETE "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds/$NEXTCLOUD_NAME" \
-H "Authorization: Bearer $K8S_TOKEN"
Status and Monitoring¶
Watch Resources (Stream Changes)¶
curl -k -X GET "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds?watch=true" \
-H "Authorization: Bearer $K8S_TOKEN" \
-H "Accept: application/json"
Get Events¶
curl -k -X GET "$K8S_API_SERVER/api/v1/namespaces/$TENANT_NAMESPACE/events?fieldSelector=involvedObject.name=$NEXTCLOUD_NAME" \
-H "Authorization: Bearer $K8S_TOKEN" | jq '.items[] | {type: .type, reason: .reason, message: .message, time: .lastTimestamp}'
List All Nextclouds (All Namespaces)¶
curl -k -X GET "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/nextclouds" \
-H "Authorization: Bearer $K8S_TOKEN" | jq '.items[] | {
name: .metadata.name,
namespace: .metadata.namespace,
phase: .status.phase,
url: .status.url
}'
Complete Example: Tenant Onboarding¶
#!/bin/bash
set -e
# Configuration
export TENANT_NAME="tenant-a"
export TENANT_NAMESPACE="tenant-a"
export NEXTCLOUD_NAME="main-cloud"
export DOMAIN="tenant-a.example.com"
echo "==> Creating namespace for $TENANT_NAME..."
curl -k -X POST "$K8S_API_SERVER/api/v1/namespaces" \
-H "Authorization: Bearer $K8S_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"apiVersion": "v1",
"kind": "Namespace",
"metadata": {
"name": "'$TENANT_NAMESPACE'",
"labels": {
"tenant": "'$TENANT_NAME'",
"managed-by": "nextcloud-operator"
}
}
}' | jq '.metadata.name'
echo "==> Creating Nextcloud instance from pool..."
curl -k -X POST "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds" \
-H "Authorization: Bearer $K8S_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"apiVersion": "k8s.bnerd.com/v1alpha1",
"kind": "Nextcloud",
"metadata": {
"name": "'$NEXTCLOUD_NAME'"
},
"spec": {
"poolSelector": {"matchLabels": {"profile": "basic"}},
"ingress": {"host": "'$DOMAIN'", "tls": {"enabled": true}}
}
}' | jq '{name: .metadata.name, namespace: .metadata.namespace}'
echo "==> Waiting for Nextcloud to be ready..."
for i in {1..60}; do
STATUS=$(curl -s "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds/$NEXTCLOUD_NAME" \
-H "Authorization: Bearer $K8S_TOKEN" | jq -r '.status.phase')
if [ "$STATUS" = "Ready" ]; then
echo "==> Nextcloud is ready!"
break
fi
echo " Status: $STATUS (attempt $i/60)"
sleep 5
done
echo "==> Getting Nextcloud details..."
curl -k -s "$K8S_API_SERVER/apis/k8s.bnerd.com/v1alpha1/namespaces/$TENANT_NAMESPACE/nextclouds/$NEXTCLOUD_NAME" \
-H "Authorization: Bearer $K8S_TOKEN" | jq '{
name: .metadata.name,
phase: .status.phase,
url: .status.url,
admin: .status.admin,
instanceRef: .status.instanceRef
}'
echo "==> Onboarding complete!"
Error Handling¶
Common HTTP Status Codes¶
| Code | Meaning |
|---|---|
| 200 | Request successful |
| 201 | Resource created |
| 404 | Resource doesn't exist |
| 409 | Resource already exists |
| 422 | Invalid resource specification |
| 403 | Insufficient permissions |
| 401 | Invalid or missing authentication |
Tips¶
- Use
jqfor JSON parsing - Save tokens securely — don't hardcode in scripts
- Use
kubectl proxyfor simpler authentication during development - Check events on errors for detailed information
- Use
?watch=truefor real-time resource updates