Skip to content

Commit bdb6cb0

Browse files
CSTACKEX-270: Automation for the template cache workflows (#99)
### Description This PR... <!--- Describe your changes in DETAIL - And how has behaviour functionally changed. --> <!-- For new features, provide link to FS, dev ML discussion etc. --> <!-- In case of bug fix, the expected and actual behaviours, steps to reproduce. --> <!-- When "Fixes: #<id>" is specified, the issue/PR will automatically be closed when this PR gets merged --> <!-- For addressing multiple issues/PRs, use multiple "Fixes: #<id>" --> <!-- Fixes: # --> <!--- ******************************************************************************* --> <!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE DOCUMENTATION. --> <!--- PLEASE PUT AN 'X' in only **ONE** box --> <!--- ******************************************************************************* --> ### Types of changes - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] New feature (non-breaking change which adds functionality) - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] Enhancement (improves an existing feature and functionality) - [ ] Cleanup (Code refactoring and cleanup, that may add test cases) - [ ] Build/CI - [x] Test (unit or integration test code) ### Feature/Enhancement Scale or Bug Severity #### Feature/Enhancement Scale - [ ] Major - [ ] Minor #### Bug Severity - [ ] BLOCKER - [ ] Critical - [ ] Major - [ ] Minor - [ ] Trivial ### Screenshots (if appropriate): ### How Has This Been Tested? <!-- Please describe in detail how you tested your changes. --> <!-- Include details of your testing environment, and the tests you ran to --> #### How did you try to break this feature and the system with this change? <!-- see how your change affects other areas of the code, etc. --> <!-- Please read the [CONTRIBUTING](https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md) document -->
1 parent a463f96 commit bdb6cb0

14 files changed

Lines changed: 2052 additions & 170 deletions

‎test/integration/plugins/ontap/README.md‎

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ for the deployment, health-gate, and artifact contracts.
4343
test/integration/plugins/ontap/
4444
├── ontap.cfg # Environment config (IPs, credentials, zone info)
4545
├── ontap_test_base.py # Shared base class and ONTAP REST client
46-
├── TEST_CASES.md # Full test case reference table (62 tests)
46+
├── TEST_CASES.md # Full test case reference table (72 tests)
4747
├── README.md # This file
4848
│
4949
├── nfs3/
@@ -53,8 +53,10 @@ test/integration/plugins/ontap/
5353
│ │ └── test_zone_scoped_pool.py # Zone-scoped pool (attachZone)
5454
│ ├── volume/
5555
│ │ └── test_volume_lifecycle.py # Volume create/delete/negative-delete
56-
│ └── instance/
57-
│ └── test_vm_volume_attach.py # Pool + volume + VM + attach/detach
56+
│ ├── instance/
57+
│ │ └── test_vm_volume_attach.py # Pool + volume + VM + attach/detach + template cache
58+
│ └── template/
59+
│ └── test_template_cache_negative.py # Template-cache boundary cases
5860
│
5961
└── iscsi/
6062
├── pool/
@@ -63,8 +65,10 @@ test/integration/plugins/ontap/
6365
│ └── test_zone_scoped_pool.py # Zone-scoped iSCSI pool
6466
├── volume/
6567
│ └── test_volume_lifecycle.py # LUN create/delete/negative-delete
66-
└── instance/
67-
└── test_vm_volume_attach.py # Pool + LUN + VM + attach/LUN-map lifecycle
68+
├── instance/
69+
│ └── test_vm_volume_attach.py # Pool + LUN + VM + attach/LUN-map lifecycle + template cache
70+
└── template/
71+
└── test_template_cache_negative.py # Template-cache boundary cases
6872
```
6973

7074
---
@@ -147,29 +151,36 @@ The test classes read `storageIP`, `svmName`, `username`, and `password` from th
147151
Run all suites for one protocol in a single batch, then inspect consolidated results:
148152

149153
```bash
150-
# iSCSI only — 5 suites, ~30–45 min
154+
# iSCSI only — 6 suites, ~40–60 min
151155
bash test/integration/plugins/ontap/run_tests.sh iscsi
152156

153-
# NFS3 only — 5 suites, ~30–45 min
157+
# NFS3 only — 6 suites, ~40–60 min
154158
bash test/integration/plugins/ontap/run_tests.sh nfs3
155159

156-
# Full plugin validation: iSCSI batch, then NFS3 batch (~60–90 min)
160+
# Full plugin validation: iSCSI batch, then NFS3 batch
157161
bash test/integration/plugins/ontap/run_tests.sh both
158162

159163
# Default (setup_zone + iscsi + nfs3; excludes cleanup_zone)
160164
bash test/integration/plugins/ontap/run_tests.sh
161165
bash test/integration/plugins/ontap/run_tests.sh all
166+
167+
# Template-cache negative / boundary suites only
168+
# (the template-cache happy path runs inside the VM attach suites)
169+
bash test/integration/plugins/ontap/run_tests.sh nfs3_template_cache_negative
170+
bash test/integration/plugins/ontap/run_tests.sh iscsi_template_cache_negative
162171
```
163172

164-
Each protocol batch runs suites in this order: pool lifecycle → pool with volumes → volume lifecycle → zone-scoped pool → VM attach (last).
173+
Each protocol batch runs suites in this order: pool lifecycle → pool with volumes → volume lifecycle → zone-scoped pool → VM attach (includes template cache seed / reuse / survive) → template cache negative (last).
165174

166175
| Command | What it runs |
167176
|---------|--------------|
168-
| `run_tests.sh iscsi` | All 5 iSCSI suites + unified iSCSI report |
169-
| `run_tests.sh nfs3` | All 5 NFS3 suites + unified NFS3 report |
177+
| `run_tests.sh iscsi` | All 6 iSCSI suites + unified iSCSI report |
178+
| `run_tests.sh nfs3` | All 6 NFS3 suites + unified NFS3 report |
170179
| `run_tests.sh both` | iSCSI batch, then NFS3 batch + combined report |
171180
| `run_tests.sh all` | `setup_zone`, then `both` (iSCSI before NFS3) |
172181
| `run_tests.sh nfs3_workflow` | Single suite by tag (unchanged) |
182+
| `run_tests.sh nfs3_template_cache_negative` | NFS3 template-cache boundary/negative suite |
183+
| `run_tests.sh iscsi_template_cache_negative` | iSCSI template-cache boundary/negative suite |
173184
| `run_tests.sh setup_zone` | Zone setup only |
174185
| `run_tests.sh cleanup_zone` | Zone teardown (manual; destructive) |
175186

@@ -323,12 +334,14 @@ self.assertEqual(result.state, "Maintenance")
323334
| NFS3 Pool with Volumes | `nfs3/pool/test_pool_with_volumes.py` | 7 | Same + live volume present; negative delete guard |
324335
| NFS3 Zone-Scoped Pool | `nfs3/pool/test_zone_scoped_pool.py` | 4 | Zone scope — all hosts connected via `attachZone` |
325336
| NFS3 Volume Lifecycle | `nfs3/volume/test_volume_lifecycle.py` | 5 | Volume is metadata-only; FlexVol unchanged on delete |
326-
| NFS3 VM + Volume Attach | `nfs3/instance/test_vm_volume_attach.py` | 8 | Full VM lifecycle with hot-plug/detach |
337+
| NFS3 VM + Volume Attach | `nfs3/instance/test_vm_volume_attach.py` | 10 | Full VM lifecycle with hot-plug/detach; ROOT on tagged pool seeds/reuses template cache, which survives VM delete |
338+
| NFS3 Template Cache Negative | `nfs3/template/test_template_cache_negative.py` | 3 | Tag mismatch; undersized pool; out-of-band cache delete |
327339
| iSCSI Pool Lifecycle | `iscsi/pool/test_pool_lifecycle.py` | 8 | Create, disable, enable, maintenance, delete + igroups |
328340
| iSCSI Pool with Volumes | `iscsi/pool/test_pool_with_volumes.py` | 7 | Same + live LUN present; negative delete guard |
329341
| iSCSI Zone-Scoped Pool | `iscsi/pool/test_zone_scoped_pool.py` | 4 | Zone scope |
330342
| iSCSI Volume Lifecycle | `iscsi/volume/test_volume_lifecycle.py` | 5 | LUN created per CS volume; LUN removed on delete |
331-
| iSCSI VM + Volume Attach | `iscsi/instance/test_vm_volume_attach.py` | 8 | Full VM lifecycle; LUN-maps on VM start/stop/detach |
343+
| iSCSI VM + Volume Attach | `iscsi/instance/test_vm_volume_attach.py` | 10 | Full VM lifecycle; LUN-maps on VM start/stop/detach; ROOT on tagged pool seeds/reuses `cs_tmpl_*` LUN cache |
344+
| iSCSI Template Cache Negative | `iscsi/template/test_template_cache_negative.py` | 3 | Tag mismatch; undersized pool; out-of-band cache delete |
332345

333346
For the goal, dependencies, and exact success criteria of every individual test, see [TEST_CASES.md](TEST_CASES.md).
334347

‎test/integration/plugins/ontap/TEST_CASES.md‎

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
# ONTAP Integration Test Cases
2121

22-
Complete reference for all 62 test cases across 10 test suites.
22+
Complete reference for all 72 test cases across 12 test suites.
2323
Each suite is sequential — tests must run in numbered order; each step builds on state created by the previous step.
2424

2525
---
@@ -114,18 +114,20 @@ Each suite is sequential — tests must run in numbered order; each step builds
114114
**File:** `nfs3/instance/test_vm_volume_attach.py`
115115
**Class:** `TestOntapVMVolumeAttach`
116116
**Tag:** `vm_volume_workflow`
117-
**Total:** 8 tests | **Scope:** end-to-end — NFS3 pool, data volume, running VM, attach/detach lifecycle
117+
**Total:** 10 tests | **Scope:** end-to-end — NFS3 pool, data volume, running VM (ROOT on the ONTAP pool via a tagged compute offering), primary template cache seed / reuse / survive VM delete, attach/detach lifecycle
118118

119119
| # | Test method | Goal | Depends on | CloudStack success criteria | ONTAP success criteria | Type |
120120
|---|-------------|------|------------|-----------------------------|------------------------|------|
121-
| 01 | `test_01_create_nfs3_pool` | Create NFS3 ONTAP primary storage pool | setUpClass (zone, cluster, template) | `pool.state == "Up"` | FlexVol `online`; export policy present | positive |
121+
| 01 | `test_01_create_nfs3_pool` | Create NFS3 ONTAP primary storage pool tagged `<storagePoolTags>-tmpl-cache` | setUpClass (zone, cluster, template, tagged SO) | `pool.state == "Up"` | FlexVol `online`; export policy present | positive |
122122
| 02 | `test_02_create_ontap_data_volume` | Allocate a CloudStack data volume on the ONTAP pool | test_01 (`pool`) | Volume non-None and listed in `listVolumes` | FlexVol still `online` | positive |
123-
| 03 | `test_03_deploy_vm` | Deploy a VM using the first available ready KVM template | test_02 (`pool`, `volume`) | `vm.state == "Running"`; template auto-selected from `listTemplates` | n/a | positive |
123+
| 03 | `test_03_deploy_vm` | Deploy a VM with the tagged SO — ROOT on ONTAP; seeds template cache | test_02 (`pool`, `volume`) | `vm.state == "Running"`; ROOT `storageid` = pool; `template_spool_ref` Ready/DOWNLOADED | Cache file present at spool `install_path` | positive |
124+
| 03a | `test_03a_deploy_second_vm_reuses_template_cache` | Deploy VM-2 — reuses cache | test_03 | VM-2 Running; ROOT on pool; still exactly one `template_spool_ref` | Same cache file (no second cache) | positive |
125+
| 03b | `test_03b_expunge_second_vm_template_cache_survives` | Expunge VM-2 — cache must remain (lazy GC) | test_03a | spool_ref still Ready | Cache file still present | positive |
124126
| 04 | `test_04_attach_volume_to_vm` | Attach the ONTAP data volume to the running VM (hot-plug) | test_03 (`vm`, `volume`) | `volume.virtualmachineid == vm.id`; `attachVolume` job succeeds | FlexVol `online`; after attach, a data file matching volume UUID present in FlexVol (`list_files_in_volume`) | positive |
125127
| 05 | `test_05_stop_vm_export_retained` | Stop the running VM with volume attached | test_04 | `vm.state == "Stopped"` | FlexVol still `online`; NFS export policy still present | positive |
126128
| 06 | `test_06_start_vm_volume_accessible` | Start the stopped VM | test_05 | `vm.state == "Running"` | FlexVol still `online` | positive |
127129
| 07 | `test_07_detach_volume_from_vm` | Hot-detach the ONTAP volume from the running VM (TDS Detach NFS3) | test_06 (`vm`, `volume`) | `volume.virtualmachineid` cleared; `volume.state == "Ready"` | FlexVol still `online`; data file **still present** (NFS3: file persists until `deleteVolume`, not on detach) | positive |
128-
| 08 | `test_08_destroy_vm_and_cleanup` | Destroy VM (expunge), delete volume, enter maintenance, delete pool | test_07 | VM no longer listed; volume no longer listed; pool no longer listed | FlexVol deleted; export policy deleted | cleanup |
130+
| 08 | `test_08_destroy_vm_and_cleanup` | Destroy VM (expunge), delete volume, enter maintenance, force-delete pool | test_07 | VM no longer listed; spool_ref still Ready after VM expunge; volume no longer listed; pool no longer listed | Cache file present after VM expunge; FlexVol deleted; export policy deleted | cleanup |
129131

130132
---
131133

@@ -206,23 +208,55 @@ Each suite is sequential — tests must run in numbered order; each step builds
206208
**File:** `iscsi/instance/test_vm_volume_attach.py`
207209
**Class:** `TestOntapVMVolumeAttachISCSI`
208210
**Tag:** `iscsi_vm_workflow`
209-
**Total:** 8 tests | **Scope:** end-to-end — iSCSI pool, data volume (LUN), running VM, attach/stop/start/detach lifecycle
211+
**Total:** 10 tests | **Scope:** end-to-end — iSCSI pool, data volume (LUN), running VM (ROOT on the ONTAP pool via a tagged compute offering), `cs_tmpl_<templateId>` LUN cache seed / reuse / survive VM delete, attach/stop/start/detach lifecycle
210212

211213
| # | Test method | Goal | Depends on | CloudStack success criteria | ONTAP success criteria | Type |
212214
|---|-------------|------|------------|-----------------------------|------------------------|------|
213-
| 01 | `test_01_create_iscsi_pool` | Create iSCSI ONTAP primary storage pool | setUpClass | `pool.state == "Up"`, `pool.type == "OntapiSCSI"` | FlexVol `online`; igroup per cluster host with host IQN | positive |
215+
| 01 | `test_01_create_iscsi_pool` | Create iSCSI ONTAP primary storage pool tagged `<storagePoolTags>-tmpl-cache` | setUpClass (tagged SO) | `pool.state == "Up"`, `pool.type == "OntapiSCSI"` | FlexVol `online`; igroup per cluster host with host IQN | positive |
214216
| 02 | `test_02_create_ontap_data_volume` | Allocate a CloudStack data volume (creates a LUN in the FlexVol) | test_01 (`pool`) | Volume non-None | ≥1 LUN in FlexVol | positive |
215-
| 03 | `test_03_deploy_vm` | Deploy VM using first ready KVM template; verify 0 LUN-maps exist before attach | test_02 (`volume`) | `vm.state == "Running"`; 0 LUN-maps on ONTAP | 0 LUN-maps (`list_lun_maps_for_volume` returns empty) | positive |
217+
| 03 | `test_03_deploy_vm` | Deploy VM with the tagged SO — ROOT on ONTAP; seeds `cs_tmpl_*`; verify 0 data-volume LUN-maps before attach | test_02 (`volume`) | `vm.state == "Running"`; ROOT on pool; spool_ref Ready (`local_path` = LUN uuid) | Exactly one `/vol/<flex>/cs_tmpl_<id>` LUN; 0 data-volume LUN-maps | positive |
218+
| 03a | `test_03a_deploy_second_vm_reuses_template_cache` | Deploy VM-2 — reuse cache | test_03 | VM-2 Running; ROOT on pool; still one spool_ref | Still one `cs_tmpl_*`; non-cache LUN count +1 | positive |
219+
| 03b | `test_03b_expunge_second_vm_template_cache_survives` | Expunge VM-2 — cache LUN remains | test_03a | spool_ref still Ready | VM-2 ROOT LUN gone (non-cache count back to baseline); `cs_tmpl_*` still present | positive |
216220
| 04 | `test_04_attach_volume_to_vm` | Hot-attach the ONTAP iSCSI volume to the running VM — a LUN-map is created (TDS SN 27) | test_03 (`vm`, `volume`) | `volume.virtualmachineid == vm.id` | ≥1 LUN-map linking the LUN to the host's igroup | positive |
217221
| 05 | `test_05_stop_vm_lun_unmapped` | Stop VM — LUN-maps must be removed (TDS VM Stop iSCSI) | test_04 | `vm.state == "Stopped"` | 0 LUN-maps; LUN itself **still present** in FlexVol | positive |
218222
| 06 | `test_06_start_vm_lun_remapped` | Start VM — LUN-maps must be re-created (TDS VM Start iSCSI) | test_05 | `vm.state == "Running"` | ≥1 LUN-map re-created | positive |
219223
| 07 | `test_07_detach_volume_from_vm` | Hot-detach the iSCSI volume from the running VM (TDS Detach iSCSI) | test_06 (`vm`, `volume`) | `volume.virtualmachineid` cleared | 0 LUN-maps; LUN still in FlexVol | positive ⚠️ |
220-
| 08 | `test_08_destroy_vm_and_cleanup` | Destroy VM (expunge), delete volume, enter maintenance, delete pool | test_07 | VM gone; volume gone; pool gone | FlexVol deleted; all LUNs and igroups deleted | cleanup |
224+
| 08 | `test_08_destroy_vm_and_cleanup` | Destroy VM (expunge), delete volume, enter maintenance, delete pool | test_07 | VM gone; spool_ref still Ready after VM expunge; volume gone; pool gone | `cs_tmpl_*` present after VM expunge; FlexVol deleted; all LUNs and igroups deleted | cleanup |
221225

222226
> ⚠️ **test_07 known status:** iSCSI hot-detach from a running VM relies on the KVM guest acknowledging the SCSI device removal. On this environment the guest does not acknowledge in time, causing CloudStack error 530. This is a KVM-host-level or guest-template limitation, not a test code defect. All other 61 tests pass.
223227
224228
---
225229

230+
## Suite 11 — NFS3 Template Cache Negative / Boundary
231+
232+
**File:** `nfs3/template/test_template_cache_negative.py`
233+
**Class:** `TestOntapNfs3TemplateCacheNegative`
234+
**Tag:** `nfs3_template_cache_negative`
235+
**Total:** 3 tests | **Scope:** Boundary conditions for NFS3 primary template cache (isolated from happy path)
236+
237+
| # | Test method | Goal | Depends on | CloudStack success criteria | ONTAP success criteria | Type |
238+
|---|-------------|------|------------|-----------------------------|------------------------|------|
239+
| 01 | `test_01_tag_mismatch_does_not_seed_cache` | SO tags ≠ pool tags | setUpClass | Deploy may succeed elsewhere; ROOT not on ONTAP pool; no `template_spool_ref` for pool | No cache file for template on FlexVol | negative |
240+
| 02 | `test_02_undersized_pool_deploy_fails` | Matching tags but `capacitybytes` ≪ template size | setUpClass | Deploy fails / never Running; spool_ref not Ready/DOWNLOADED | No cache file | negative |
241+
| 03 | `test_03_deleted_cache_blocks_reuse` | Seed cache, delete file out-of-band, redeploy | setUpClass | spool_ref still Ready after ONTAP delete; second deploy fails | Cache file absent after delete | negative |
242+
243+
---
244+
245+
## Suite 12 — iSCSI Template Cache Negative / Boundary
246+
247+
**File:** `iscsi/template/test_template_cache_negative.py`
248+
**Class:** `TestOntapIscsiTemplateCacheNegative`
249+
**Tag:** `iscsi_template_cache_negative`
250+
**Total:** 3 tests | **Scope:** Boundary conditions for iSCSI primary template cache (isolated from happy path)
251+
252+
| # | Test method | Goal | Depends on | CloudStack success criteria | ONTAP success criteria | Type |
253+
|---|-------------|------|------------|-----------------------------|------------------------|------|
254+
| 01 | `test_01_tag_mismatch_does_not_seed_cache` | SO tags ≠ pool tags | setUpClass | ROOT not on ONTAP pool; no `template_spool_ref` | No `cs_tmpl_*` LUN | negative |
255+
| 02 | `test_02_undersized_pool_deploy_fails` | Matching tags but undersized capacity | setUpClass | Deploy fails; spool_ref not Ready/DOWNLOADED | No `cs_tmpl_*` LUN | negative |
256+
| 03 | `test_03_deleted_cache_blocks_reuse` | Seed cache, delete LUN out-of-band, redeploy | setUpClass | spool_ref still Ready; second deploy fails | `cs_tmpl_*` absent after delete | negative |
257+
258+
---
259+
226260
## Cross-suite summary
227261

228262
| Suite | Protocol | Scope | Tests | Status |
@@ -231,10 +265,12 @@ Each suite is sequential — tests must run in numbered order; each step builds
231265
| NFS3 Pool with Volumes | NFS3 | Cluster | 7 | ✅ |
232266
| NFS3 Zone-Scoped Pool | NFS3 | Zone | 4 | ✅ |
233267
| NFS3 Volume Lifecycle | NFS3 | Cluster | 5 | ✅ |
234-
| NFS3 VM + Volume Attach | NFS3 | Cluster | 8 | ✅ |
268+
| NFS3 VM + Volume Attach | NFS3 | Cluster | 10 | 🆕 +2 template cache |
269+
| NFS3 Template Cache Negative | NFS3 | Cluster | 3 | 🆕 |
235270
| iSCSI Pool Lifecycle | iSCSI | Cluster | 8 | ✅ |
236271
| iSCSI Pool with Volumes | iSCSI | Cluster | 7 | ✅ |
237272
| iSCSI Zone-Scoped Pool | iSCSI | Zone | 4 | ✅ |
238273
| iSCSI Volume Lifecycle | iSCSI | Cluster | 5 | ✅ |
239-
| iSCSI VM + Volume Attach | iSCSI | Cluster | 8 | ⚠️ 7/8 |
240-
| **Total** | | | **62** | **61 passing** |
274+
| iSCSI VM + Volume Attach | iSCSI | Cluster | 10 | ⚠️ 7/8 + 🆕 2 template cache |
275+
| iSCSI Template Cache Negative | iSCSI | Cluster | 3 | 🆕 |
276+
| **Total** | | | **72** | |
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.

0 commit comments

Comments
 (0)