Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@
import org.apache.cloudstack.secstorage.heuristics.HeuristicType;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.storage.heuristics.presetvariables.Account;
import org.apache.cloudstack.storage.heuristics.presetvariables.Domain;
import org.apache.cloudstack.storage.heuristics.presetvariables.DownloadDetails;
import org.apache.cloudstack.storage.heuristics.presetvariables.PresetVariables;
import org.apache.cloudstack.storage.heuristics.presetvariables.SecondaryStorage;
import org.apache.cloudstack.storage.heuristics.presetvariables.Snapshot;
Expand Down Expand Up @@ -78,6 +81,9 @@ public class HeuristicRuleHelper {
@Inject
private DataCenterDao zoneDao;

@Inject
private TemplateDataStoreDao templateDataStoreDao;

/**
* Returns the {@link DataStore} object if the zone, specified by the ID, has an active heuristic rule for the given {@link HeuristicType}.
* It returns null otherwise.
Expand Down Expand Up @@ -187,6 +193,23 @@ protected Template setTemplatePresetVariable(VMTemplateVO templateVO) {
template.setName(templateVO.getName());
template.setFormat(templateVO.getFormat().toString());
template.setHypervisorType(templateVO.getHypervisorType().toString());
template.setTemplateType(templateVO.getTemplateType().toString());
template.setPublic(templateVO.isPublicTemplate());

List<DownloadDetails> downloadDetails = new ArrayList<>();
List<TemplateDataStoreVO> templateDataStoreVOs = templateDataStoreDao.listByTemplate(templateVO.getId());

for (TemplateDataStoreVO templateDataStoreVO : templateDataStoreVOs) {
ImageStoreVO imageStore = imageStoreDao.findById(templateDataStoreVO.getDataStoreId());

DownloadDetails downloadDetail = new DownloadDetails();
downloadDetail.setDataStoreId(imageStore.getUuid());
downloadDetail.setDownloadState(templateDataStoreVO.getDownloadState());
downloadDetails.add(downloadDetail);
}

template.setDownloadDetails(downloadDetails);


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

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

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

if (dataStore == null) {
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 " +
"returning a valid UUID.", scriptReturn, rule));
logger.debug("Script did not return a valid secondary storage; allocating resource in any available secondary storage.");
}

return dataStore;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.heuristics.presetvariables;

import com.cloud.storage.VMTemplateStorageResourceAssoc;

public class DownloadDetails extends GenericHeuristicPresetVariable {

private String dataStoreId;

private VMTemplateStorageResourceAssoc.Status downloadState;

public String getDataStoreId() {
return dataStoreId;
}

public void setDataStoreId(String dataStoreId) {
this.dataStoreId = dataStoreId;
}

public VMTemplateStorageResourceAssoc.Status getDownloadState() {
return downloadState;
}

public void setDownloadState(VMTemplateStorageResourceAssoc.Status downloadState) {
this.downloadState = downloadState;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// under the License.
package org.apache.cloudstack.storage.heuristics.presetvariables;

import java.util.List;

public class Template extends GenericHeuristicPresetVariable {

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

private String templateType;

private boolean isPublic;

private List<DownloadDetails> downloadDetails;

public String getHypervisorType() {
return hypervisorType;
}
Expand All @@ -47,4 +53,21 @@ public String getTemplateType() {
public void setTemplateType(String templateType) {
this.templateType = templateType;
}

public boolean isPublic() {
return isPublic;
}

public void setPublic(boolean isPublic) {
this.isPublic = isPublic;
}

public List<DownloadDetails> getDownloadDetails() {
return downloadDetails;
}

public void setDownloadDetails(List<DownloadDetails> downloadDetails) {
this.downloadDetails = downloadDetails;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.cloudstack.secstorage.HeuristicVO;
import org.apache.cloudstack.secstorage.dao.SecondaryStorageHeuristicDao;
import org.apache.cloudstack.secstorage.heuristics.HeuristicType;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.heuristics.presetvariables.PresetVariables;
import org.apache.cloudstack.utils.jsinterpreter.JsInterpreter;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -64,6 +65,9 @@ public class HeuristicRuleHelperTest {
@Mock
DataStore dataStoreMock;

@Mock
TemplateDataStoreDao templateDataStoreDaoMock;

@Mock
Logger loggerMock;

Expand All @@ -76,6 +80,7 @@ public void setUp() {
Mockito.doReturn("template-name").when(vmTemplateVOMock).getName();
Mockito.doReturn(Storage.ImageFormat.QCOW2).when(vmTemplateVOMock).getFormat();
Mockito.doReturn(Hypervisor.HypervisorType.KVM).when(vmTemplateVOMock).getHypervisorType();
Mockito.doReturn(Storage.TemplateType.USER).when(vmTemplateVOMock).getTemplateType();
Mockito.doReturn("snapshot-name").when(snapshotInfoMock).getName();
Mockito.doReturn(1024L).when(snapshotInfoMock).getSize();
Mockito.doReturn(Hypervisor.HypervisorType.VMware).when(snapshotInfoMock).getHypervisorType();
Expand Down Expand Up @@ -166,31 +171,28 @@ public void buildPresetVariablesTestWithSnapshotHeuristicTypeShouldSetVolumeAndS
}

@Test
public void interpretHeuristicRuleTestHeuristicRuleDoesNotReturnAStringShouldThrowCloudRuntimeException() {
public void interpretHeuristicRuleTestHeuristicRuleDoesNotReturnAStringShouldReturnNull() {
String heuristicRule = "1";

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

String expectedMessage = String.format("Error while interpreting heuristic rule [%s], the rule did not return a String.", heuristicRule);
CloudRuntimeException assertThrows = Assert.assertThrows(CloudRuntimeException.class,
() -> heuristicRuleHelperSpy.interpretHeuristicRule(heuristicRule, HeuristicType.TEMPLATE, volumeVOMock, 1L));
Assert.assertEquals(expectedMessage, assertThrows.getMessage());
DataStore result = heuristicRuleHelperSpy.interpretHeuristicRule(heuristicRule, HeuristicType.TEMPLATE, volumeVOMock, 1L);

Assert.assertNull(result);
}

@Test
public void interpretHeuristicRuleTestHeuristicRuleReturnAStringWithInvalidUuidShouldThrowCloudRuntimeException() {
public void interpretHeuristicRuleTestHeuristicRuleReturnAStringWithInvalidUuidShouldReturnNull() {
String heuristicRule = "'uuid'";

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

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 " +
"returning a valid UUID.", "uuid", heuristicRule);
CloudRuntimeException assertThrows = Assert.assertThrows(CloudRuntimeException.class,
() -> heuristicRuleHelperSpy.interpretHeuristicRule(heuristicRule, HeuristicType.TEMPLATE, volumeVOMock, 1L));
Assert.assertEquals(expectedMessage, assertThrows.getMessage());
DataStore result = heuristicRuleHelperSpy.interpretHeuristicRule(heuristicRule, HeuristicType.TEMPLATE, volumeVOMock, 1L);

Assert.assertNull(result);
}

@Test
Expand Down
Loading