mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
orchestration,hypervisor: allow custom manufacture, product for vm (#9163)
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
b215abc30a
commit
1e12a80210
@ -84,6 +84,8 @@ public class VirtualMachineTO {
|
||||
Map<String, String> extraConfig = new HashMap<>();
|
||||
Map<Long, String> networkIdToNetworkNameMap = new HashMap<>();
|
||||
DeployAsIsInfoTO deployAsIsInfo;
|
||||
String metadataManufacturer;
|
||||
String metadataProductName;
|
||||
|
||||
public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader,
|
||||
String os, boolean enableHA, boolean limitCpuUse, String vncPassword) {
|
||||
@ -429,6 +431,22 @@ public class VirtualMachineTO {
|
||||
this.deployAsIsInfo = deployAsIsInfo;
|
||||
}
|
||||
|
||||
public String getMetadataManufacturer() {
|
||||
return metadataManufacturer;
|
||||
}
|
||||
|
||||
public void setMetadataManufacturer(String metadataManufacturer) {
|
||||
this.metadataManufacturer = metadataManufacturer;
|
||||
}
|
||||
|
||||
public String getMetadataProductName() {
|
||||
return metadataProductName;
|
||||
}
|
||||
|
||||
public void setMetadataProductName(String metadataProductName) {
|
||||
this.metadataProductName = metadataProductName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("VM {id: \"%s\", name: \"%s\", uuid: \"%s\", type: \"%s\"}", id, name, uuid, type);
|
||||
|
||||
@ -87,6 +87,20 @@ public interface VirtualMachineManager extends Manager {
|
||||
ConfigKey<String> MetadataCustomCloudName = new ConfigKey<>("Advanced", String.class, "metadata.custom.cloud.name", "",
|
||||
"If provided, a custom cloud-name in cloud-init metadata", true, ConfigKey.Scope.Zone);
|
||||
|
||||
ConfigKey<String> VmMetadataManufacturer = new ConfigKey<>("Advanced", String.class,
|
||||
"vm.metadata.manufacturer", "Apache Software Foundation",
|
||||
"If provided, a custom manufacturer will be used in the instance metadata. When an empty" +
|
||||
"value is set then default manufacturer will be 'Apache Software Foundation'. " +
|
||||
"A custom manufacturer may break cloud-init functionality with CloudStack datasource. Please " +
|
||||
"refer documentation", true, ConfigKey.Scope.Zone);
|
||||
ConfigKey<String> VmMetadataProductName = new ConfigKey<>("Advanced", String.class,
|
||||
"vm.metadata.product", "",
|
||||
"If provided, a custom product name will be used in the instance metadata. When an empty" +
|
||||
"value is set then default product name will be 'CloudStack <HYPERVISIOR_NAME> Hypervisor'. " +
|
||||
"A custom product name may break cloud-init functionality with CloudStack datasource. Please " +
|
||||
"refer documentation",
|
||||
true, ConfigKey.Scope.Zone);
|
||||
|
||||
interface Topics {
|
||||
String VM_POWER_STATE = "vm.powerstate";
|
||||
}
|
||||
|
||||
@ -49,15 +49,6 @@ import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
import javax.persistence.EntityExistsException;
|
||||
|
||||
import com.cloud.configuration.Resource;
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.domain.dao.DomainDao;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.network.vpc.VpcVO;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.event.ActionEventUtils;
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
|
||||
import org.apache.cloudstack.annotation.AnnotationService;
|
||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||
@ -160,6 +151,7 @@ import com.cloud.api.query.dao.UserVmJoinDao;
|
||||
import com.cloud.api.query.vo.DomainRouterJoinVO;
|
||||
import com.cloud.api.query.vo.UserVmJoinVO;
|
||||
import com.cloud.capacity.CapacityManager;
|
||||
import com.cloud.configuration.Resource;
|
||||
import com.cloud.dc.ClusterDetailsDao;
|
||||
import com.cloud.dc.ClusterDetailsVO;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
@ -178,6 +170,9 @@ import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
||||
import com.cloud.deploy.DeploymentPlanningManager;
|
||||
import com.cloud.deploy.DeploymentPlanningManagerImpl;
|
||||
import com.cloud.deployasis.dao.UserVmDeployAsIsDetailsDao;
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.domain.dao.DomainDao;
|
||||
import com.cloud.event.ActionEventUtils;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.event.UsageEventUtils;
|
||||
import com.cloud.event.UsageEventVO;
|
||||
@ -189,6 +184,7 @@ import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.InsufficientServerCapacityException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.OperationTimedoutException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.exception.StorageAccessException;
|
||||
import com.cloud.exception.StorageUnavailableException;
|
||||
@ -211,6 +207,8 @@ import com.cloud.network.dao.NetworkDetailsDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.network.router.VirtualRouter;
|
||||
import com.cloud.network.security.SecurityGroupManager;
|
||||
import com.cloud.network.vpc.VpcVO;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.offering.DiskOffering;
|
||||
import com.cloud.offering.DiskOfferingInfo;
|
||||
import com.cloud.offering.NetworkOffering;
|
||||
@ -246,6 +244,7 @@ import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.ResourceLimitService;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.DateUtil;
|
||||
import com.cloud.utils.Journal;
|
||||
@ -281,6 +280,7 @@ import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.snapshot.VMSnapshotManager;
|
||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, VmWorkJobHandler, Listener, Configurable {
|
||||
|
||||
@ -1101,6 +1101,19 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
markVolumesInPool(vm, answer);
|
||||
}
|
||||
|
||||
protected void updateVmMetadataManufacturerAndProduct(VirtualMachineTO vmTO, VMInstanceVO vm) {
|
||||
String metadataManufacturer = VmMetadataManufacturer.valueIn(vm.getDataCenterId());
|
||||
if (StringUtils.isBlank(metadataManufacturer)) {
|
||||
metadataManufacturer = VmMetadataManufacturer.defaultValue();
|
||||
}
|
||||
vmTO.setMetadataManufacturer(metadataManufacturer);
|
||||
String metadataProduct = VmMetadataProductName.valueIn(vm.getDataCenterId());
|
||||
if (StringUtils.isBlank(metadataManufacturer)) {
|
||||
metadataProduct = String.format("CloudStack %s Hypervisor", vm.getHypervisorType().toString());
|
||||
}
|
||||
vmTO.setMetadataProductName(metadataProduct);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfile.Param, Object> params, final DeploymentPlan planToDeploy, final DeploymentPlanner planner)
|
||||
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
|
||||
@ -1259,6 +1272,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
vmGuru.finalizeVirtualMachineProfile(vmProfile, dest, ctx);
|
||||
|
||||
final VirtualMachineTO vmTO = hvGuru.implement(vmProfile);
|
||||
updateVmMetadataManufacturerAndProduct(vmTO, vm);
|
||||
|
||||
checkAndSetEnterSetupMode(vmTO, params);
|
||||
|
||||
@ -4742,7 +4756,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
||||
VmOpLockStateRetry, VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval,
|
||||
VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, VmConfigDriveForceHostCacheUse, VmConfigDriveUseHostCacheOnUnsupportedPool,
|
||||
HaVmRestartHostUp, ResourceCountRunningVMsonly, AllowExposeHypervisorHostname, AllowExposeHypervisorHostnameAccountLevel, SystemVmRootDiskSize,
|
||||
AllowExposeDomainInMetadata, MetadataCustomCloudName
|
||||
AllowExposeDomainInMetadata, MetadataCustomCloudName, VmMetadataManufacturer, VmMetadataProductName
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -37,26 +37,18 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.api.query.vo.UserVmJoinVO;
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.domain.DomainVO;
|
||||
import com.cloud.domain.dao.DomainDao;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.network.vpc.VpcVO;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
import org.apache.cloudstack.framework.config.ScopedConfigStorage;
|
||||
import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -76,24 +68,34 @@ import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.StopAnswer;
|
||||
import com.cloud.agent.api.StopCommand;
|
||||
import com.cloud.agent.api.routing.NetworkElementCommand;
|
||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||
import com.cloud.api.query.dao.UserVmJoinDao;
|
||||
import com.cloud.api.query.vo.UserVmJoinVO;
|
||||
import com.cloud.dc.ClusterDetailsDao;
|
||||
import com.cloud.dc.ClusterDetailsVO;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.Pod;
|
||||
import com.cloud.dc.dao.ClusterDao;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.deploy.DataCenterDeployment;
|
||||
import com.cloud.deploy.DeployDestination;
|
||||
import com.cloud.deploy.DeploymentPlan;
|
||||
import com.cloud.deploy.DeploymentPlanner;
|
||||
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
||||
import com.cloud.deploy.DeploymentPlanningManager;
|
||||
import com.cloud.domain.DomainVO;
|
||||
import com.cloud.domain.dao.DomainDao;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.hypervisor.HypervisorGuruManager;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.network.vpc.VpcVO;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.org.Cluster;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
@ -115,7 +117,9 @@ import com.cloud.storage.dao.VMTemplateZoneDao;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.utils.Journal;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.Ternary;
|
||||
@ -220,8 +224,12 @@ public class VirtualMachineManagerImplTest {
|
||||
@Mock
|
||||
protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
|
||||
|
||||
private ConfigDepotImpl configDepotImpl;
|
||||
private boolean updatedConfigKeyDepot = false;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
ReflectionTestUtils.getField(VirtualMachineManager.VmMetadataManufacturer, "s_depot");
|
||||
virtualMachineManagerImpl.setHostAllocators(new ArrayList<>());
|
||||
|
||||
when(vmInstanceMock.getId()).thenReturn(vmInstanceVoMockId);
|
||||
@ -251,6 +259,13 @@ public class VirtualMachineManagerImplTest {
|
||||
virtualMachineManagerImpl.setStoragePoolAllocators(storagePoolAllocators);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if (updatedConfigKeyDepot) {
|
||||
ReflectionTestUtils.setField(VirtualMachineManager.VmMetadataManufacturer, "s_depot", configDepotImpl);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testaddHostIpToCertDetailsIfConfigAllows() {
|
||||
Host vmHost = mock(Host.class);
|
||||
@ -1236,4 +1251,48 @@ public class VirtualMachineManagerImplTest {
|
||||
assertFalse(result.get(1L));
|
||||
assertTrue(result.get(2L));
|
||||
}
|
||||
|
||||
private void overrideVmMetadataConfigValue(final String manufacturer, final String product) {
|
||||
ConfigKey configKey = VirtualMachineManager.VmMetadataManufacturer;
|
||||
this.configDepotImpl = (ConfigDepotImpl)ReflectionTestUtils.getField(configKey, "s_depot");
|
||||
ConfigDepotImpl configDepot = Mockito.mock(ConfigDepotImpl.class);
|
||||
ScopedConfigStorage storage = Mockito.mock(ScopedConfigStorage.class);
|
||||
Mockito.when(storage.getConfigValue(Mockito.anyLong(), Mockito.eq(configKey))).thenReturn(manufacturer);
|
||||
Mockito.when(storage.getConfigValue(Mockito.anyLong(), Mockito.eq(VirtualMachineManager.VmMetadataProductName)))
|
||||
.thenReturn(product);
|
||||
Mockito.when(configDepot.findScopedConfigStorage(configKey)).thenReturn(storage);
|
||||
Mockito.when(configDepot.findScopedConfigStorage(VirtualMachineManager.VmMetadataProductName)).thenReturn(storage);
|
||||
ReflectionTestUtils.setField(configKey, "s_depot", configDepot);
|
||||
updatedConfigKeyDepot = true;
|
||||
}
|
||||
|
||||
private Pair<VirtualMachineTO, VMInstanceVO> getDummyVmTOAndVm() {
|
||||
VirtualMachineTO virtualMachineTO = new VirtualMachineTO(1L, "VM", VirtualMachine.Type.User, 1,
|
||||
1000, 256, 512, VirtualMachineTemplate.BootloaderType.HVM, "OS",
|
||||
false, false, "Pass");
|
||||
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
|
||||
Mockito.when(vm.getDataCenterId()).thenReturn(1L);
|
||||
return new Pair<>(virtualMachineTO, vm);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateVmMetadataManufacturerAndProductDefaultManufacturer() {
|
||||
overrideVmMetadataConfigValue("", "");
|
||||
Pair<VirtualMachineTO, VMInstanceVO> pair = getDummyVmTOAndVm();
|
||||
VirtualMachineTO to = pair.first();
|
||||
virtualMachineManagerImpl.updateVmMetadataManufacturerAndProduct(to, pair.second());
|
||||
Assert.assertEquals(VirtualMachineManager.VmMetadataManufacturer.defaultValue(), to.getMetadataManufacturer());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateVmMetadataManufacturerAndProductCustomManufacturer() {
|
||||
String manufacturer = UUID.randomUUID().toString();
|
||||
String product = UUID.randomUUID().toString();
|
||||
overrideVmMetadataConfigValue(manufacturer, product);
|
||||
Pair<VirtualMachineTO, VMInstanceVO> pair = getDummyVmTOAndVm();
|
||||
VirtualMachineTO to = pair.first();
|
||||
virtualMachineManagerImpl.updateVmMetadataManufacturerAndProduct(to, pair.second());
|
||||
Assert.assertEquals(manufacturer, to.getMetadataManufacturer());
|
||||
Assert.assertEquals(product, to.getMetadataProductName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2838,6 +2838,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||
GuestDef guest = new GuestDef();
|
||||
|
||||
configureGuestAndVMHypervisorType(vmTO, vm, guest);
|
||||
guest.setManufacturer(vmTO.getMetadataManufacturer());
|
||||
guest.setProduct(vmTO.getMetadataProductName());
|
||||
guest.setGuestArch(guestCpuArch != null ? guestCpuArch : vmTO.getArch());
|
||||
guest.setMachineType(isGuestAarch64() ? VIRT : PC);
|
||||
guest.setBootType(GuestDef.BootType.BIOS);
|
||||
|
||||
@ -95,6 +95,8 @@ public class LibvirtVMDef {
|
||||
}
|
||||
|
||||
private GuestType _type;
|
||||
private String manufacturer;
|
||||
private String product;
|
||||
private BootType _boottype;
|
||||
private BootMode _bootmode;
|
||||
private String _arch;
|
||||
@ -124,6 +126,22 @@ public class LibvirtVMDef {
|
||||
return _type;
|
||||
}
|
||||
|
||||
public String getManufacturer() {
|
||||
return manufacturer;
|
||||
}
|
||||
|
||||
public void setManufacturer(String manufacturer) {
|
||||
this.manufacturer = manufacturer;
|
||||
}
|
||||
|
||||
public String getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
public void setProduct(String product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
public void setNvram(String nvram) { _nvram = nvram; }
|
||||
|
||||
public void setNvramTemplate(String nvramTemplate) { _nvramTemplate = nvramTemplate; }
|
||||
@ -182,8 +200,8 @@ public class LibvirtVMDef {
|
||||
|
||||
guestDef.append("<sysinfo type='smbios'>\n");
|
||||
guestDef.append("<system>\n");
|
||||
guestDef.append("<entry name='manufacturer'>Apache Software Foundation</entry>\n");
|
||||
guestDef.append("<entry name='product'>CloudStack " + _type.toString() + " Hypervisor</entry>\n");
|
||||
guestDef.append("<entry name='manufacturer'>" + getManufacturer() +"</entry>\n");
|
||||
guestDef.append("<entry name='product'>" + getProduct() + "</entry>\n");
|
||||
guestDef.append("<entry name='uuid'>" + _uuid + "</entry>\n");
|
||||
guestDef.append("</system>\n");
|
||||
guestDef.append("</sysinfo>\n");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user