OpenNebula Plugin E2E Integration Test Report
Date: 2026-02-17
Branch: feature/opennebula-plugin
Agent version: waldur-site-agent-opennebula 0.7.0
Waldur version: 8.0.3+20.g73e8d5a42
Environment
| Component | Detail |
|---|---|
| OpenNebula API | http://lab-1910.opennebula.cloud:2633/RPC2 |
| OpenNebula Sunstone | https://lab-1910.opennebula.cloud/ |
| Waldur API | http://localhost:8000/api/ |
| VDC Offering UUID | 26767d945b3b44d7966ea7562a6e70d3 |
| VM Offering UUID | 32f2b0ddb15d42e2b86d10b7668014cc |
| Config file | opennebula-test-config.yaml |
Test Summary
| # | Operation | Resource | Result | Duration |
|---|---|---|---|---|
| 1 | CREATE | VDC e2e-vdc |
PASS | ~35s |
| 2 | UPDATE | VDC e2e-vdc (limits x2) |
PASS | ~1s |
| 3 | TERMINATE | VDC e2e-vdc |
PASS | ~3s |
| 4 | CREATE | VM e2e-test-vm (Small plan) |
PASS | ~11s |
| 5 | UPDATE | VM e2e-test-vm (Small → Medium) |
PASS | ~11s |
| 6 | TERMINATE | VM e2e-test-vm |
PASS | <1s |
VDC Lifecycle
VDC Order Flow
sequenceDiagram
participant U as User/API
participant W as Waldur
participant A as Site Agent
participant ONE as OpenNebula
Note over U,ONE: VDC CREATE
U->>W: POST /marketplace-orders/ (type=Create)
W-->>U: order_uuid (pending-provider)
A->>W: GET /marketplace-orders/ (poll)
A->>W: POST /approve_by_provider/
A->>ONE: group.allocate("e2e-vdc")
A->>ONE: vdc.allocate("e2e-vdc")
A->>ONE: vdc.addgroup(vdc_id, group_id)
A->>ONE: vdc.addcluster(vdc_id, zone, cluster_ids)
A->>ONE: vn.allocate("e2e-vdc_internal", 10.0.1.0/24)
A->>ONE: vn → cluster, vn → vdc
A->>ONE: vrouter.allocate("e2e-vdc_router")
A->>ONE: vrouter.instantiate(vr_id, template=1)
ONE-->>A: VR VM created
A->>ONE: poll VM state until RUNNING
A->>ONE: secgroup.allocate("e2e-vdc_default")
A->>W: POST /set_backend_id/ ("e2e-vdc")
A->>W: POST /set_limits/ (cpu=4, ram=4096, ...)
A->>W: POST /set_state_done/
Note over U,ONE: VDC UPDATE (limits)
U->>W: POST /update_limits/ (cpu=8, ram=8192, ...)
W-->>U: order_uuid (pending-provider)
A->>W: GET /marketplace-orders/ (poll)
A->>W: POST /approve_by_provider/
A->>ONE: group.quota(group_id, new_quotas)
A->>W: POST /set_state_done/
Note over U,ONE: VDC TERMINATE
U->>W: POST /terminate/
W-->>U: order_uuid (pending-provider)
A->>W: GET /marketplace-orders/ (poll)
A->>W: POST /approve_by_provider/
A->>ONE: user.delete(admin_user)
A->>ONE: vrouter.delete(vr_id) → cascades to VR VM
A->>ONE: wait for VR VM → DONE
A->>ONE: vn.delete(vnet_id)
A->>ONE: secgroup.delete(sg_id)
A->>ONE: vdc.delete(vdc_id)
A->>ONE: group.delete(group_id)
A->>W: POST /set_state_done/
Test 1: VDC CREATE
Input:
| Field | Value |
|---|---|
| Order type | Create |
| Resource name | e2e-vdc |
| Project | Protein Structure Prediction |
| Plan | Default |
| Limits | cpu=4, ram=4096 MB, storage=20480 MB, floating_ip=2 |
OpenNebula resources created:
| Resource | Name | ID |
|---|---|---|
| Group | e2e-vdc |
201 |
| VDC | e2e-vdc |
184 |
| VNet | e2e-vdc_internal |
56 |
| Virtual Router | e2e-vdc_router |
27 |
| VR VM | e2e-vdc_router_vm |
32 |
| Security Group | e2e-vdc_default |
105 |
VR VM state transitions:
1 2 3 4 | |
Result:
| Field | Value |
|---|---|
| Order state | done |
| Resource state | OK |
| Backend ID | e2e-vdc |
| Waldur limits | cpu=4, ram=4096, storage=20480, floating_ip=2 |
Test 2: VDC UPDATE (Limits)
Input:
| Field | Value |
|---|---|
| Order type | Update |
| API endpoint | POST /marketplace-resources/{uuid}/update_limits/ |
| New limits | cpu=8, ram=8192 MB, storage=40960 MB, floating_ip=4 |
Result:
| Field | Before | After |
|---|---|---|
| cpu | 4 | 8 |
| ram | 4096 | 8192 |
| storage | 20480 | 40960 |
| floating_ip | 2 | 4 |
| Order state | — | done |
Agent log excerpt:
1 2 3 | |
Test 3: VDC TERMINATE
Input:
| Field | Value |
|---|---|
| Order type | Terminate |
| API endpoint | POST /marketplace-resources/{uuid}/terminate/ |
OpenNebula resources deleted (in order):
| Step | Resource | Name | ID |
|---|---|---|---|
| 1 | Admin user | e2e-vdc_admin |
13 |
| 2 | VR (+ VM) | e2e-vdc_router |
27 |
| 3 | VNet | e2e-vdc_internal |
56 |
| 4 | Security Group | e2e-vdc_default |
105 |
| 5 | VDC | (already deleted) | — |
| 6 | Group | e2e-vdc |
201 |
Result:
| Field | Value |
|---|---|
| Order state | done |
| Resource state | Terminated |
VM Lifecycle
VM Order Flow
sequenceDiagram
participant U as User/API
participant W as Waldur
participant A as Site Agent
participant ONE as OpenNebula
Note over U,ONE: VM CREATE (Small plan)
U->>W: POST /marketplace-orders/ (type=Create)
W-->>U: order_uuid (pending-provider)
A->>W: GET /marketplace-orders/ (poll)
A->>W: POST /approve_by_provider/
A->>ONE: template.instantiate(template=2, group=agrisense-9)
ONE-->>A: VM ID = 33
A->>ONE: poll VM state until RUNNING
A->>W: POST /set_backend_id/ ("33")
A->>W: POST /set_state_done/
Note over U,ONE: VM UPDATE (Small → Medium)
U->>W: POST /switch_plan/ (plan=Medium)
W-->>U: order_uuid (pending-provider)
A->>W: GET /marketplace-orders/ (poll)
A->>W: POST /approve_by_provider/
A->>ONE: vm.action("poweroff", 33)
A->>ONE: poll VM → POWEROFF
A->>ONE: vm.resize(33, vcpu=1, ram=1024)
A->>ONE: vm.action("resume", 33)
A->>ONE: poll VM → RUNNING
A->>W: POST /set_state_done/
Note over U,ONE: VM TERMINATE
U->>W: POST /terminate/
W-->>U: order_uuid (pending-provider)
A->>W: GET /marketplace-orders/ (poll)
A->>W: POST /approve_by_provider/
A->>ONE: vm.action("terminate-hard", 33)
A->>W: POST /set_state_done/
Test 4: VM CREATE
Input:
| Field | Value |
|---|---|
| Order type | Create |
| Resource name | e2e-test-vm |
| Project | Protein Structure Prediction |
| Plan | Small (1 vCPU, 512 MB RAM, 2 GB disk) |
| Template ID | 2 (from backend_settings) |
| Parent VDC | agrisense-9 |
VM state transitions:
1 2 3 | |
Result:
| Field | Value |
|---|---|
| Order state | done |
| Resource state | OK |
| Backend ID | 33 (numeric OpenNebula VM ID) |
| Plan | Small (1 vCPU, 512 MB RAM, 2 GB disk) |
| OpenNebula VM ID | 33 |
| VDC group | agrisense-9 |
Test 5: VM UPDATE (Plan Change / Resize)
Input:
| Field | Value |
|---|---|
| Order type | Update (switch_plan) |
| API endpoint | POST /marketplace-resources/{uuid}/switch_plan/ |
| Old plan | Small (1 vCPU, 512 MB RAM, 2 GB disk) |
| New plan | Medium (1 vCPU, 1 GB RAM, 5 GB disk) |
Resize sequence:
1 2 3 4 5 6 | |
Result:
| Field | Before | After |
|---|---|---|
| Plan | Small | Medium |
| vCPU | 1 | 1 |
| RAM | 512 MB | 1024 MB |
| Disk | 2048 MB | 5120 MB |
| Order state | — | done |
| VM state | OK | OK |
Test 6: VM TERMINATE
Input:
| Field | Value |
|---|---|
| Order type | Terminate |
| API endpoint | POST /marketplace-resources/{uuid}/terminate/ |
Result:
| Field | Value |
|---|---|
| Action | vm.action("terminate-hard", 33) |
| Order state | done |
| Resource state | Terminated |
| Agent log | Terminated VM ID 33 |
Open Questions
-
VDC backend_id should be numeric group ID — Currently the VDC backend_id stores the group name (e.g.
e2e-vdc). For consistency with the VM backend_id (which uses the numeric OpenNebula VM ID), the VDC should use the numeric OpenNebula group ID. This eliminates group pool scans for every operation. -
VDC teardown ordering — The current teardown deletes VR first, then waits for VR VMs to reach DONE before deleting VNet. Should there be a retry/backoff for the VNet deletion instead of (or in addition to) the explicit wait?
-
Plan-based VM limits — The VM offering uses FIXED component plans (Small, Medium, Large) so
limitsin the Waldur resource stays empty. The plan quotas drive the resize. Should the agent also setlimitson the resource to reflect the actual VM specs after creation/resize? -
Disk resize — The resize flow handles CPU and RAM but disk resize via
vm.diskresizecan fail on some storage backends. What is the expected behavior when disk shrink is requested (currently logged as warning and skipped)? -
Error recovery for partial VDC creation — If VR VM fails to reach RUNNING during VDC creation, the rollback deletes VR, VNet, but the group and VDC objects remain. Should the rollback also clean up group and VDC?
Configuration Used
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |