| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -49,6 +49,7 @@ | |||
| 49 | 49 | import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; | |
| 50 | 50 | import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; | |
| 51 | 51 | import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; | |
| 52 | + import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; | ||
| 52 | 53 | import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; | |
| 53 | 54 | import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; | |
| 54 | 55 | import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; | |
@@ -1368,11 +1369,13 @@ private void createManagedVolumeCopyTemplateAsync(VolumeInfo volumeInfo, Primary | |||
| 1368 | 1369 | primaryDataStore.setDetails(details); | |
| 1369 | 1370 | ||
| 1370 | 1371 | grantAccess(volumeInfo, destHost, primaryDataStore); | |
| 1371 | - volumeInfo = volFactory.getVolume(volumeInfo.getId(), primaryDataStore); | ||
| 1372 | - // For Netapp ONTAP iscsiName or Lun path is available only after grantAccess | ||
| 1373 | - String managedStoreTarget = ObjectUtils.defaultIfNull(volumeInfo.get_iScsiName(), volumeInfo.getUuid()); | ||
| 1374 | - details.put(PrimaryDataStore.MANAGED_STORE_TARGET, managedStoreTarget); | ||
| 1375 | - primaryDataStore.setDetails(details); | ||
| 1372 | + if (DataStoreProvider.ONTAP_PLUGIN_NAME.equals(primaryDataStore.getStorageProviderName())) { | ||
| 1373 | + // For Netapp ONTAP iscsiName or Lun path is available only after grantAccess | ||
| 1374 | + volumeInfo = volFactory.getVolume(volumeInfo.getId(), primaryDataStore); | ||
| 1375 | + String managedStoreTarget = ObjectUtils.defaultIfNull(volumeInfo.get_iScsiName(), volumeInfo.getUuid()); | ||
| 1376 | + details.put(PrimaryDataStore.MANAGED_STORE_TARGET, managedStoreTarget); | ||
| 1377 | + primaryDataStore.setDetails(details); | ||
| 1378 | + } | ||
| 1376 | 1379 | ||
| 1377 | 1380 | try { | |
| 1378 | 1381 | motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -37,9 +37,7 @@ | |||
| 37 | 37 | <jackson-databind.version>2.13.4</jackson-databind.version> | |
| 38 | 38 | <assertj.version>3.24.2</assertj.version> | |
| 39 | 39 | <junit-jupiter.version>5.8.1</junit-jupiter.version> | |
| 40 | - <mockito.version>3.12.4</mockito.version> | ||
| 41 | - <mockito-junit-jupiter.version>5.2.0</mockito-junit-jupiter.version> | ||
| 42 | - <byte-buddy-agent.version>1.11.13</byte-buddy-agent.version> | ||
| 40 | + <byte-buddy-agent.version>1.15.11</byte-buddy-agent.version> | ||
| 43 | 41 | </properties> | |
| 44 | 42 | <dependencyManagement> | |
| 45 | 43 | <dependencies> | |
@@ -105,21 +103,13 @@ | |||
| 105 | 103 | <dependency> | |
| 106 | 104 | <groupId>org.mockito</groupId> | |
| 107 | 105 | <artifactId>mockito-core</artifactId> | |
| 108 | - <version>${mockito.version}</version> | ||
| 106 | + <version>${cs.mockito.version}</version> | ||
| 109 | 107 | <scope>test</scope> | |
| 110 | 108 | </dependency> | |
| 111 | 109 | <dependency> | |
| 112 | 110 | <groupId>org.mockito</groupId> | |
| 113 | 111 | <artifactId>mockito-junit-jupiter</artifactId> | |
| 114 | - <version>${mockito-junit-jupiter.version}</version> | ||
| 115 | - <scope>test</scope> | ||
| 116 | - </dependency> | ||
| 117 | - | ||
| 118 | - <!-- Mockito Inline (for static method mocking) --> | ||
| 119 | - <dependency> | ||
| 120 | - <groupId>org.mockito</groupId> | ||
| 121 | - <artifactId>mockito-inline</artifactId> | ||
| 122 | - <version>${mockito.version}</version> | ||
| 112 | + <version>${cs.mockito.version}</version> | ||
| 123 | 113 | <scope>test</scope> | |
| 124 | 114 | </dependency> | |
| 125 | 115 | <dependency> | |
@@ -163,7 +153,6 @@ | |||
| 163 | 153 | <artifactId>maven-surefire-plugin</artifactId> | |
| 164 | 154 | <version>${maven-surefire-plugin.version}</version> | |
| 165 | 155 | <configuration> | |
| 166 | - <skipTests>false</skipTests> | ||
| 167 | 156 | <includes> | |
| 168 | 157 | <include>**/*Test.java</include> | |
| 169 | 158 | </includes> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -413,7 +413,7 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore | |||
| 413 | 413 | private void grantAccessIscsi(Host host, VolumeVO volumeVO, Map<String, String> details, String svmName, StoragePoolVO storagePool) { | |
| 414 | 414 | String cloudStackVolumeName = volumeDetailsDao.findDetail(volumeVO.getId(), OntapStorageConstants.LUN_DOT_NAME).getValue(); | |
| 415 | 415 | UnifiedSANStrategy sanStrategy = (UnifiedSANStrategy) OntapStorageUtils.getStrategyByStoragePoolDetails(details); | |
| 416 | - String accessGroupName = OntapStorageUtils.getIgroupName(svmName, host.getName()); | ||
| 416 | + String accessGroupName = OntapStorageUtils.getIgroupName(svmName, host.getUuid()); | ||
| 417 | 417 | ||
| 418 | 418 | // Validate if Igroup exist ONTAP for this host as we may be using delete_on_unmap= true and igroup may be deleted by ONTAP automatically | |
| 419 | 419 | Map<String, String> getAccessGroupMap = Map.of( | |
@@ -506,7 +506,7 @@ private void revokeAccessForVolume(StoragePoolVO storagePool, VolumeVO volumeVO, | |||
| 506 | 506 | String svmName = details.get(OntapStorageConstants.SVM_NAME); | |
| 507 | 507 | ||
| 508 | 508 | if (ProtocolType.ISCSI.name().equalsIgnoreCase(details.get(OntapStorageConstants.PROTOCOL))) { | |
| 509 | - String accessGroupName = OntapStorageUtils.getIgroupName(svmName, host.getName()); | ||
| 509 | + String accessGroupName = OntapStorageUtils.getIgroupName(svmName, host.getUuid()); | ||
| 510 | 510 | ||
| 511 | 511 | // Retrieve LUN name from volume details; if missing, volume may not have been fully created | |
| 512 | 512 | VolumeDetailVO lunDetail = volumeDetailsDao.findDetail(volumeVO.getId(), OntapStorageConstants.LUN_DOT_NAME); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,9 +19,11 @@ | |||
| 19 | 19 | ||
| 20 | 20 | package org.apache.cloudstack.storage.feign.model; | |
| 21 | 21 | ||
| 22 | + import com.fasterxml.jackson.annotation.JsonCreator; | ||
| 22 | 23 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | |
| 23 | 24 | import com.fasterxml.jackson.annotation.JsonInclude; | |
| 24 | 25 | import com.fasterxml.jackson.annotation.JsonProperty; | |
| 26 | + import com.fasterxml.jackson.annotation.JsonValue; | ||
| 25 | 27 | ||
| 26 | 28 | import java.util.List; | |
| 27 | 29 | import java.util.Objects; | |
@@ -50,6 +52,9 @@ public class Volume { | |||
| 50 | 52 | @JsonProperty("space") | |
| 51 | 53 | private VolumeSpace space; | |
| 52 | 54 | ||
| 55 | + @JsonProperty("guarantee") | ||
| 56 | + private Guarantee guarantee; | ||
| 57 | + | ||
| 53 | 58 | @JsonProperty("anti_ransomware") | |
| 54 | 59 | private AntiRansomware antiRansomware; | |
| 55 | 60 | ||
@@ -112,6 +117,14 @@ public void setSpace(VolumeSpace space) { | |||
| 112 | 117 | this.space = space; | |
| 113 | 118 | } | |
| 114 | 119 | ||
| 120 | + public Guarantee getGuarantee() { | ||
| 121 | + return guarantee; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + public void setGuarantee(Guarantee guarantee) { | ||
| 125 | + this.guarantee = guarantee; | ||
| 126 | + } | ||
| 127 | + | ||
| 115 | 128 | public AntiRansomware getAntiRansomware() { | |
| 116 | 129 | return antiRansomware; | |
| 117 | 130 | } | |
@@ -139,4 +152,66 @@ public boolean equals(Object o) { | |||
| 139 | 152 | public int hashCode() { | |
| 140 | 153 | return Objects.hashCode(uuid); | |
| 141 | 154 | } | |
| 155 | + | ||
| 156 | + public static class Guarantee { | ||
| 157 | + | ||
| 158 | + /** | ||
| 159 | + * ONTAP FlexVolume space guarantee (provisioning) type. | ||
| 160 | + * <ul> | ||
| 161 | + * <li>{@link #NONE} - thin provisioning (space is not reserved up front)</li> | ||
| 162 | + * <li>{@link #VOLUME} - thick provisioning (full volume size is reserved on the aggregate)</li> | ||
| 163 | + * </ul> | ||
| 164 | + */ | ||
| 165 | + public enum TypeEnum { | ||
| 166 | + NONE("none"), | ||
| 167 | + | ||
| 168 | + VOLUME("volume"); | ||
| 169 | + | ||
| 170 | + private String value; | ||
| 171 | + | ||
| 172 | + TypeEnum(String value) { | ||
| 173 | + this.value = value; | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + @JsonValue | ||
| 177 | + public String getValue() { | ||
| 178 | + return value; | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + @Override | ||
| 182 | + public String toString() { | ||
| 183 | + return String.valueOf(value); | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + @JsonCreator | ||
| 187 | + public static TypeEnum fromValue(String text) { | ||
| 188 | + if (text == null) return null; | ||
| 189 | + for (TypeEnum b : TypeEnum.values()) { | ||
| 190 | + if (text.equalsIgnoreCase(b.value)) { | ||
| 191 | + return b; | ||
| 192 | + } | ||
| 193 | + } | ||
| 194 | + return null; | ||
| 195 | + } | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + @JsonProperty("type") | ||
| 199 | + private TypeEnum type; | ||
| 200 | + | ||
| 201 | + public Guarantee() { | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + public Guarantee(TypeEnum type) { | ||
| 205 | + this.type = type; | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + public TypeEnum getType() { | ||
| 209 | + return type; | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | + public void setType(TypeEnum type) { | ||
| 213 | + this.type = type; | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + | ||
| 142 | 217 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -337,9 +337,12 @@ public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.Hyper | |||
| 337 | 337 | logger.error("attachZone : Storage Pool not found for id: " + dataStore.getId()); | |
| 338 | 338 | throw new CloudRuntimeException("Storage Pool not found for id: " + dataStore.getId()); | |
| 339 | 339 | } | |
| 340 | - | ||
| 340 | + if (!Hypervisor.HypervisorType.KVM.equals(hypervisorType)) { | ||
| 341 | + logger.error("attachZone : ONTAP primary storage is supported only for KVM hypervisor"); | ||
| 342 | + throw new CloudRuntimeException("ONTAP primary storage is supported only for KVM hypervisor"); | ||
| 343 | + } | ||
| 341 | 344 | PrimaryDataStoreInfo primaryStore = (PrimaryDataStoreInfo)dataStore; | |
| 342 | - List<HostVO> hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), Hypervisor.HypervisorType.KVM); | ||
| 345 | + List<HostVO> hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), hypervisorType); | ||
| 343 | 346 | logger.debug(String.format("In createPool. Attaching the pool to each of the hosts in %s.", hostsToConnect)); | |
| 344 | 347 | ||
| 345 | 348 | Map<String, String> details = storagePoolDetailsDao.listDetailsKeyPairs(primaryStore.getId()); | |
@@ -364,7 +367,7 @@ public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.Hyper | |||
| 364 | 367 | return false; | |
| 365 | 368 | } | |
| 366 | 369 | } | |
| 367 | - _dataStoreHelper.attachZone(dataStore); | ||
| 370 | + _dataStoreHelper.attachZone(dataStore, hypervisorType); | ||
| 368 | 371 | return true; | |
| 369 | 372 | } | |
| 370 | 373 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -49,6 +49,7 @@ | |||
| 49 | 49 | import org.apache.logging.log4j.Logger; | |
| 50 | 50 | ||
| 51 | 51 | import java.util.HashMap; | |
| 52 | + import java.util.ArrayList; | ||
| 52 | 53 | import java.util.List; | |
| 53 | 54 | import java.util.Map; | |
| 54 | 55 | import java.util.Objects; | |
@@ -135,31 +136,42 @@ public boolean connect() { | |||
| 135 | 136 | logger.error("No aggregates are assigned to SVM " + svmName); | |
| 136 | 137 | throw new CloudRuntimeException("No aggregates are assigned to SVM " + svmName); | |
| 137 | 138 | } | |
| 139 | + // Collect all online aggregates assigned to the SVM. Capacity-based selection is | ||
| 140 | + // intentionally deferred to createStorageVolume(name, size), which validates the | ||
| 141 | + // available space against the actual requested volume size. | ||
| 142 | + List<Aggregate> eligibleAggregates = new ArrayList<>(); | ||
| 138 | 143 | for (Aggregate aggr : aggrs) { | |
| 139 | 144 | logger.debug("Found aggregate: " + aggr.getName() + " with UUID: " + aggr.getUuid()); | |
| 140 | 145 | Aggregate aggrResp = aggregateFeignClient.getAggregateByUUID(authHeader, aggr.getUuid()); | |
| 141 | 146 | if (aggrResp == null) { | |
| 142 | 147 | logger.warn("Aggregate details response is null for aggregate " + aggr.getName() + ". Skipping."); | |
| 143 | - break; | ||
| 148 | + continue; | ||
| 144 | 149 | } | |
| 145 | 150 | if (!Objects.equals(aggrResp.getState(), Aggregate.StateEnum.ONLINE)) { | |
| 146 | 151 | logger.warn("Aggregate " + aggr.getName() + " is not in online state. Skipping this aggregate."); | |
| 147 | 152 | continue; | |
| 148 | - } else if (aggrResp.getSpace() == null || aggrResp.getAvailableBlockStorageSpace() == null || | ||
| 149 | - aggrResp.getAvailableBlockStorageSpace() <= storage.getSize().doubleValue()) { | ||
| 150 | - logger.warn("Aggregate " + aggr.getName() + " does not have sufficient available space. Skipping this aggregate."); | ||
| 151 | - continue; | ||
| 152 | 153 | } | |
| 153 | - logger.info("Selected aggregate: " + aggr.getName() + " for volume operations."); | ||
| 154 | - this.aggregates = List.of(aggr); | ||
| 155 | - break; | ||
| 154 | + logger.debug("Aggregate " + aggr.getName() + " is online and eligible for volume operations."); | ||
| 155 | + eligibleAggregates.add(aggr); | ||
| 156 | 156 | } | |
| 157 | - if (this.aggregates == null || this.aggregates.isEmpty()) { | ||
| 158 | - logger.error("No suitable aggregates found on SVM " + svmName + " for volume creation."); | ||
| 159 | - throw new CloudRuntimeException("No suitable aggregates found on SVM " + svmName + " for volume creation."); | ||
| 157 | + if (eligibleAggregates.isEmpty()) { | ||
| 158 | + logger.error("No suitable aggregates found on SVM " + svmName + " for volume operations."); | ||
| 159 | + throw new CloudRuntimeException("No suitable aggregates found on SVM " + svmName + " for volume operations."); | ||
| 160 | 160 | } | |
| 161 | + this.aggregates = eligibleAggregates; | ||
| 162 | + logger.info("Found " + eligibleAggregates.size() + " online aggregate(s) on SVM " + svmName + " for volume operations."); | ||
| 161 | 163 | ||
| 162 | 164 | logger.info("Successfully connected to ONTAP cluster and validated ONTAP details provided"); | |
| 165 | + } catch (FeignException.Unauthorized e) { | ||
| 166 | + logger.error("Authentication failed while connecting to ONTAP cluster at " + storage.getStorageIP() + | ||
| 167 | + ". Please verify the username and password.", e); | ||
| 168 | + throw new CloudRuntimeException("Authentication failed: Invalid credentials for ONTAP cluster at " + | ||
| 169 | + storage.getStorageIP() + ". Please verify the username and password."); | ||
| 170 | + } catch (FeignException.Forbidden e) { | ||
| 171 | + logger.error("Authorization failed while connecting to ONTAP cluster at " + storage.getStorageIP() + | ||
| 172 | + ". The user does not have sufficient privileges.", e); | ||
| 173 | + throw new CloudRuntimeException("Authorization failed: User does not have sufficient privileges on ONTAP cluster at " + | ||
| 174 | + storage.getStorageIP() + ". Please verify user permissions."); | ||
| 163 | 175 | } catch (Exception e) { | |
| 164 | 176 | logger.error("Failed to connect to ONTAP cluster: " + e.getMessage(), e); | |
| 165 | 177 | throw new CloudRuntimeException("Failed to connect to ONTAP cluster: " + e.getMessage(), e); | |
@@ -211,7 +223,7 @@ public Volume createStorageVolume(String volumeName, Long size) { | |||
| 211 | 223 | ||
| 212 | 224 | if (aggrResp == null) { | |
| 213 | 225 | logger.warn("Aggregate details response is null for aggregate " + aggr.getName() + ". Skipping."); | |
| 214 | - break; | ||
| 226 | + continue; | ||
| 215 | 227 | } | |
| 216 | 228 | ||
| 217 | 229 | if (!Objects.equals(aggrResp.getState(), Aggregate.StateEnum.ONLINE)) { | |
@@ -227,7 +239,7 @@ public Volume createStorageVolume(String volumeName, Long size) { | |||
| 227 | 239 | final long availableBytes = aggrResp.getAvailableBlockStorageSpace().longValue(); | |
| 228 | 240 | logger.debug("Aggregate " + aggr.getName() + " available bytes=" + availableBytes + ", requested=" + size); | |
| 229 | 241 | ||
| 230 | - if (availableBytes <= size) { | ||
| 242 | + if (availableBytes < size) { | ||
| 231 | 243 | logger.warn("Aggregate " + aggr.getName() + " does not have sufficient available space. Required=" + | |
| 232 | 244 | size + " bytes, available=" + availableBytes + " bytes. Skipping this aggregate."); | |
| 233 | 245 | continue; | |
@@ -251,6 +263,7 @@ public Volume createStorageVolume(String volumeName, Long size) { | |||
| 251 | 263 | volumeRequest.setAggregates(List.of(aggr)); | |
| 252 | 264 | volumeRequest.setSize(size); | |
| 253 | 265 | volumeRequest.setNas(nas); | |
| 266 | + volumeRequest.setGuarantee(new Volume.Guarantee(Volume.Guarantee.TypeEnum.NONE)); | ||
| 254 | 267 | try { | |
| 255 | 268 | JobResponse jobResponse = volumeFeignClient.createVolumeWithJob(authHeader, volumeRequest); | |
| 256 | 269 | if (jobResponse == null || jobResponse.getJob() == null) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -207,7 +207,7 @@ public AccessGroup createAccessGroup(AccessGroup accessGroup) { | |||
| 207 | 207 | igroupRequest.setOsType(Igroup.OsTypeEnum.Linux); | |
| 208 | 208 | ||
| 209 | 209 | for (HostVO host : accessGroup.getHostsToConnect()) { | |
| 210 | - igroupName = OntapStorageUtils.getIgroupName(svmName, host.getName()); | ||
| 210 | + igroupName = OntapStorageUtils.getIgroupName(svmName, host.getUuid()); | ||
| 211 | 211 | igroupRequest.setName(igroupName); | |
| 212 | 212 | ||
| 213 | 213 | List<Initiator> initiators = new ArrayList<>(); | |
@@ -271,7 +271,7 @@ public void deleteAccessGroup(AccessGroup accessGroup) { | |||
| 271 | 271 | //Get iGroup name per host | |
| 272 | 272 | if(!CollectionUtils.isEmpty(accessGroup.getHostsToConnect())) { | |
| 273 | 273 | for (HostVO host : accessGroup.getHostsToConnect()) { | |
| 274 | - String igroupName = OntapStorageUtils.getIgroupName(svmName, host.getName()); | ||
| 274 | + String igroupName = OntapStorageUtils.getIgroupName(svmName, host.getUuid()); | ||
| 275 | 275 | logger.info("deleteAccessGroup: iGroup name '{}'", igroupName); | |
| 276 | 276 | ||
| 277 | 277 | // Get the iGroup to retrieve its UUID | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -96,6 +96,7 @@ public class OntapStorageConstants { | |||
| 96 | 96 | public static final String IGROUP_DOT_UUID = "igroup.uuid"; | |
| 97 | 97 | public static final String UNDERSCORE = "_"; | |
| 98 | 98 | public static final String CS = "cs"; | |
| 99 | + public static final int IGROUP_NAME_MAX_LENGTH = 96; | ||
| 99 | 100 | public static final String SRC_CS_VOLUME_ID = "src_cs_volume_id"; | |
| 100 | 101 | public static final String BASE_ONTAP_FV_ID = "base_ontap_fv_id"; | |
| 101 | 102 | public static final String ONTAP_SNAP_ID = "ontap_snap_id"; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -139,10 +139,15 @@ public static StorageStrategy getStrategyByStoragePoolDetails(Map<String, String | |||
| 139 | 139 | } | |
| 140 | 140 | } | |
| 141 | 141 | ||
| 142 | - public static String getIgroupName(String svmName, String hostName) { | ||
| 143 | - //Igroup name format: cs_svmName_hostName | ||
| 144 | - String sanitizedHostName = hostName.split("\\.")[0].replaceAll("[^a-zA-Z0-9_-]", "_"); | ||
| 145 | - return OntapStorageConstants.CS + OntapStorageConstants.UNDERSCORE + svmName + OntapStorageConstants.UNDERSCORE + sanitizedHostName; | ||
| 142 | + public static String getIgroupName(String svmName, String hostUuid) { | ||
| 143 | + //Igroup name format: cs_hostUuid_svmName | ||
| 144 | + String sanitizedHostUuid = hostUuid.replaceAll("[^a-zA-Z0-9_-]", "_"); | ||
| 145 | + String igroupName = OntapStorageConstants.CS + OntapStorageConstants.UNDERSCORE + sanitizedHostUuid + OntapStorageConstants.UNDERSCORE + svmName; | ||
| 146 | + // ONTAP igroup names are limited to 96 characters; truncate if longer. | ||
| 147 | + if (igroupName.length() > OntapStorageConstants.IGROUP_NAME_MAX_LENGTH) { | ||
| 148 | + igroupName = igroupName.substring(0, OntapStorageConstants.IGROUP_NAME_MAX_LENGTH); | ||
| 149 | + } | ||
| 150 | + return igroupName; | ||
| 146 | 151 | } | |
| 147 | 152 | ||
| 148 | 153 | public static String generateExportPolicyName(String svmName, String volumeName){ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -348,6 +348,7 @@ void testGrantAccess_ClusterScope_Success() { | |||
| 348 | 348 | when(volumeVO.getId()).thenReturn(100L); | |
| 349 | 349 | ||
| 350 | 350 | when(host.getName()).thenReturn("host1"); | |
| 351 | + when(host.getUuid()).thenReturn("host-uuid-1"); | ||
| 351 | 352 | ||
| 352 | 353 | VolumeDetailVO lunNameDetail = new VolumeDetailVO(100L, OntapStorageConstants.LUN_DOT_NAME, "/vol/vol1/lun1", false); | |
| 353 | 354 | when(volumeDetailsDao.findDetail(100L, OntapStorageConstants.LUN_DOT_NAME)).thenReturn(lunNameDetail); | |
@@ -384,6 +385,7 @@ void testGrantAccess_IgroupNotFound_CreatesNewIgroup() { | |||
| 384 | 385 | // Setup - use HostVO mock since production code casts Host to HostVO | |
| 385 | 386 | HostVO hostVO = mock(HostVO.class); | |
| 386 | 387 | when(hostVO.getName()).thenReturn("host1"); | |
| 388 | + when(hostVO.getUuid()).thenReturn("host-uuid-1"); | ||
| 387 | 389 | ||
| 388 | 390 | when(dataStore.getId()).thenReturn(1L); | |
| 389 | 391 | when(volumeInfo.getType()).thenReturn(VOLUME); | |
@@ -477,6 +479,7 @@ void testRevokeAccess_ISCSIVolume_Success() { | |||
| 477 | 479 | ||
| 478 | 480 | when(host.getStorageUrl()).thenReturn("iqn.1993-08.org.debian:01:host1"); | |
| 479 | 481 | when(host.getName()).thenReturn("host1"); | |
| 482 | + when(host.getUuid()).thenReturn("host-uuid-1"); | ||
| 480 | 483 | ||
| 481 | 484 | VolumeDetailVO lunNameDetail = new VolumeDetailVO(100L, OntapStorageConstants.LUN_DOT_NAME, "/vol/vol1/lun1", false); | |
| 482 | 485 | when(volumeDetailsDao.findDetail(100L, OntapStorageConstants.LUN_DOT_NAME)).thenReturn(lunNameDetail); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments