Skip to content

Commit 250ea53

Browse files
committed
Inject the template's download state in the secondary storage selectors
1 parent 8eb162c commit 250ea53

File tree

4 files changed

+108
-16
lines changed

4 files changed

+108
-16
lines changed

server/src/main/java/org/apache/cloudstack/storage/heuristics/HeuristicRuleHelper.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@
3535
import org.apache.cloudstack.secstorage.heuristics.HeuristicType;
3636
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
3737
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
38+
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
39+
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
3840
import org.apache.cloudstack.storage.heuristics.presetvariables.Account;
3941
import org.apache.cloudstack.storage.heuristics.presetvariables.Domain;
42+
import org.apache.cloudstack.storage.heuristics.presetvariables.DownloadDetails;
4043
import org.apache.cloudstack.storage.heuristics.presetvariables.PresetVariables;
4144
import org.apache.cloudstack.storage.heuristics.presetvariables.SecondaryStorage;
4245
import org.apache.cloudstack.storage.heuristics.presetvariables.Snapshot;
@@ -78,6 +81,9 @@ public class HeuristicRuleHelper {
7881
@Inject
7982
private DataCenterDao zoneDao;
8083

84+
@Inject
85+
private TemplateDataStoreDao templateDataStoreDao;
86+
8187
/**
8288
* Returns the {@link DataStore} object if the zone, specified by the ID, has an active heuristic rule for the given {@link HeuristicType}.
8389
* It returns null otherwise.
@@ -187,6 +193,23 @@ protected Template setTemplatePresetVariable(VMTemplateVO templateVO) {
187193
template.setName(templateVO.getName());
188194
template.setFormat(templateVO.getFormat().toString());
189195
template.setHypervisorType(templateVO.getHypervisorType().toString());
196+
template.setTemplateType(templateVO.getTemplateType().toString());
197+
template.setPublic(templateVO.isPublicTemplate());
198+
199+
List<DownloadDetails> downloadDetails = new ArrayList<>();
200+
List<TemplateDataStoreVO> templateDataStoreVOs = templateDataStoreDao.listByTemplate(templateVO.getId());
201+
202+
for (TemplateDataStoreVO templateDataStoreVO : templateDataStoreVOs) {
203+
ImageStoreVO imageStore = imageStoreDao.findById(templateDataStoreVO.getDataStoreId());
204+
205+
DownloadDetails downloadDetail = new DownloadDetails();
206+
downloadDetail.setDataStoreId(imageStore.getUuid());
207+
downloadDetail.setDownloadState(templateDataStoreVO.getDownloadState());
208+
downloadDetails.add(downloadDetail);
209+
}
210+
211+
template.setDownloadDetails(downloadDetails);
212+
190213

191214
return template;
192215
}
@@ -248,28 +271,30 @@ protected Domain setDomainPresetVariable(long domainId) {
248271
* in the code scope.
249272
* <br>
250273
* <br>
251-
* The JS script needs to return a valid UUID ({@link String}) of a secondary storage, otherwise a {@link CloudRuntimeException} is thrown.
274+
* The JS script needs to either return the valid UUID ({@link String}) of a secondary storage or nothing. If a valid UUID is returned,
275+
* this method returns the specific secondary storage; if nothing is returned, this method returns null to allow allocation in any
276+
* available secondary storage; otherwise a {@link CloudRuntimeException} is thrown.
252277
* @param rule the {@link String} representing the JS script.
253278
* @param heuristicType used for building the preset variables accordingly to the {@link HeuristicType} specified.
254279
* @param obj can be from the following classes: {@link VMTemplateVO}, {@link SnapshotInfo} and {@link VolumeVO}.
255280
* They are used to retrieve attributes for injecting in the JS rule.
256281
* @param zoneId used for injecting the {@link SecondaryStorage} preset variables.
257-
* @return the {@link DataStore} returned by the script.
282+
* @return the {@link DataStore} returned by the script, or null.
258283
*/
259284
public DataStore interpretHeuristicRule(String rule, HeuristicType heuristicType, Object obj, long zoneId) {
260285
try (JsInterpreter jsInterpreter = new JsInterpreter(HEURISTICS_SCRIPT_TIMEOUT)) {
261286
buildPresetVariables(jsInterpreter, heuristicType, zoneId, obj);
262287
Object scriptReturn = jsInterpreter.executeScript(rule);
263288

264289
if (!(scriptReturn instanceof String)) {
265-
throw new CloudRuntimeException(String.format("Error while interpreting heuristic rule [%s], the rule did not return a String.", rule));
290+
logger.debug("Script did not return a string; allocating resource in any available secondary storage.");
291+
return null;
266292
}
267293

268294
DataStore dataStore = dataStoreManager.getImageStoreByUuid((String) scriptReturn);
269295

270296
if (dataStore == null) {
271-
throw new CloudRuntimeException(String.format("Unable to find a secondary storage with the UUID [%s] returned by the heuristic rule [%s]. Check if the rule is " +
272-
"returning a valid UUID.", scriptReturn, rule));
297+
logger.debug("Script did not return a valid secondary storage; allocating resource in any available secondary storage.");
273298
}
274299

275300
return dataStore;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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.
17+
package org.apache.cloudstack.storage.heuristics.presetvariables;
18+
19+
import com.cloud.storage.VMTemplateStorageResourceAssoc;
20+
21+
public class DownloadDetails extends GenericHeuristicPresetVariable {
22+
23+
private String dataStoreId;
24+
25+
private VMTemplateStorageResourceAssoc.Status downloadState;
26+
27+
public String getDataStoreId() {
28+
return dataStoreId;
29+
}
30+
31+
public void setDataStoreId(String dataStoreId) {
32+
this.dataStoreId = dataStoreId;
33+
}
34+
35+
public VMTemplateStorageResourceAssoc.Status getDownloadState() {
36+
return downloadState;
37+
}
38+
39+
public void setDownloadState(VMTemplateStorageResourceAssoc.Status downloadState) {
40+
this.downloadState = downloadState;
41+
}
42+
}

server/src/main/java/org/apache/cloudstack/storage/heuristics/presetvariables/Template.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// under the License.
1717
package org.apache.cloudstack.storage.heuristics.presetvariables;
1818

19+
import java.util.List;
20+
1921
public class Template extends GenericHeuristicPresetVariable {
2022

2123
private String hypervisorType;
@@ -24,6 +26,10 @@ public class Template extends GenericHeuristicPresetVariable {
2426

2527
private String templateType;
2628

29+
private boolean isPublic;
30+
31+
private List<DownloadDetails> downloadDetails;
32+
2733
public String getHypervisorType() {
2834
return hypervisorType;
2935
}
@@ -47,4 +53,21 @@ public String getTemplateType() {
4753
public void setTemplateType(String templateType) {
4854
this.templateType = templateType;
4955
}
56+
57+
public boolean isPublic() {
58+
return isPublic;
59+
}
60+
61+
public void setPublic(boolean isPublic) {
62+
this.isPublic = isPublic;
63+
}
64+
65+
public List<DownloadDetails> getDownloadDetails() {
66+
return downloadDetails;
67+
}
68+
69+
public void setDownloadDetails(List<DownloadDetails> downloadDetails) {
70+
this.downloadDetails = downloadDetails;
71+
}
72+
5073
}

server/src/test/java/org/apache/cloudstack/storage/heuristics/HeuristicRuleHelperTest.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.cloudstack.secstorage.HeuristicVO;
2828
import org.apache.cloudstack.secstorage.dao.SecondaryStorageHeuristicDao;
2929
import org.apache.cloudstack.secstorage.heuristics.HeuristicType;
30+
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
3031
import org.apache.cloudstack.storage.heuristics.presetvariables.PresetVariables;
3132
import org.apache.cloudstack.utils.jsinterpreter.JsInterpreter;
3233
import org.apache.logging.log4j.Logger;
@@ -64,6 +65,9 @@ public class HeuristicRuleHelperTest {
6465
@Mock
6566
DataStore dataStoreMock;
6667

68+
@Mock
69+
TemplateDataStoreDao templateDataStoreDaoMock;
70+
6771
@Mock
6872
Logger loggerMock;
6973

@@ -76,6 +80,7 @@ public void setUp() {
7680
Mockito.doReturn("template-name").when(vmTemplateVOMock).getName();
7781
Mockito.doReturn(Storage.ImageFormat.QCOW2).when(vmTemplateVOMock).getFormat();
7882
Mockito.doReturn(Hypervisor.HypervisorType.KVM).when(vmTemplateVOMock).getHypervisorType();
83+
Mockito.doReturn(Storage.TemplateType.USER).when(vmTemplateVOMock).getTemplateType();
7984
Mockito.doReturn("snapshot-name").when(snapshotInfoMock).getName();
8085
Mockito.doReturn(1024L).when(snapshotInfoMock).getSize();
8186
Mockito.doReturn(Hypervisor.HypervisorType.VMware).when(snapshotInfoMock).getHypervisorType();
@@ -166,31 +171,28 @@ public void buildPresetVariablesTestWithSnapshotHeuristicTypeShouldSetVolumeAndS
166171
}
167172

168173
@Test
169-
public void interpretHeuristicRuleTestHeuristicRuleDoesNotReturnAStringShouldThrowCloudRuntimeException() {
174+
public void interpretHeuristicRuleTestHeuristicRuleDoesNotReturnAStringShouldReturnNull() {
170175
String heuristicRule = "1";
171176

172177
Mockito.doNothing().when(heuristicRuleHelperSpy).buildPresetVariables(Mockito.any(JsInterpreter.class), Mockito.any(HeuristicType.class), Mockito.anyLong(),
173178
Mockito.any());
174179

175-
String expectedMessage = String.format("Error while interpreting heuristic rule [%s], the rule did not return a String.", heuristicRule);
176-
CloudRuntimeException assertThrows = Assert.assertThrows(CloudRuntimeException.class,
177-
() -> heuristicRuleHelperSpy.interpretHeuristicRule(heuristicRule, HeuristicType.TEMPLATE, volumeVOMock, 1L));
178-
Assert.assertEquals(expectedMessage, assertThrows.getMessage());
180+
DataStore result = heuristicRuleHelperSpy.interpretHeuristicRule(heuristicRule, HeuristicType.TEMPLATE, volumeVOMock, 1L);
181+
182+
Assert.assertNull(result);
179183
}
180184

181185
@Test
182-
public void interpretHeuristicRuleTestHeuristicRuleReturnAStringWithInvalidUuidShouldThrowCloudRuntimeException() {
186+
public void interpretHeuristicRuleTestHeuristicRuleReturnAStringWithInvalidUuidShouldReturnNull() {
183187
String heuristicRule = "'uuid'";
184188

185189
Mockito.doNothing().when(heuristicRuleHelperSpy).buildPresetVariables(Mockito.any(JsInterpreter.class), Mockito.any(HeuristicType.class), Mockito.anyLong(),
186190
Mockito.any());
187191
Mockito.doReturn(null).when(dataStoreManagerMock).getImageStoreByUuid(Mockito.anyString());
188192

189-
String expectedMessage = String.format("Unable to find a secondary storage with the UUID [%s] returned by the heuristic rule [%s]. Check if the rule is " +
190-
"returning a valid UUID.", "uuid", heuristicRule);
191-
CloudRuntimeException assertThrows = Assert.assertThrows(CloudRuntimeException.class,
192-
() -> heuristicRuleHelperSpy.interpretHeuristicRule(heuristicRule, HeuristicType.TEMPLATE, volumeVOMock, 1L));
193-
Assert.assertEquals(expectedMessage, assertThrows.getMessage());
193+
DataStore result = heuristicRuleHelperSpy.interpretHeuristicRule(heuristicRule, HeuristicType.TEMPLATE, volumeVOMock, 1L);
194+
195+
Assert.assertNull(result);
194196
}
195197

196198
@Test

0 commit comments

Comments
 (0)