diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UnmanagedInstanceResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UnmanagedInstanceResponse.java index 7a26b178591..c1156f5f23a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/UnmanagedInstanceResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/UnmanagedInstanceResponse.java @@ -79,6 +79,14 @@ public class UnmanagedInstanceResponse extends BaseResponse { @Param(description = "the operating system of the virtual machine") private String operatingSystem; + @SerializedName(ApiConstants.BOOT_MODE) + @Param(description = "indicates the boot mode") + private String bootMode; + + @SerializedName(ApiConstants.BOOT_TYPE) + @Param(description = "indicates the boot type") + private String bootType; + @SerializedName(ApiConstants.DISK) @Param(description = "the list of disks associated with the virtual machine", responseObject = UnmanagedInstanceDiskResponse.class) private Set disks; @@ -211,4 +219,20 @@ public class UnmanagedInstanceResponse extends BaseResponse { public void addNic(NicResponse nic) { this.nics.add(nic); } + + public String getBootMode() { + return bootMode; + } + + public void setBootMode(String bootMode) { + this.bootMode = bootMode; + } + + public String getBootType() { + return bootType; + } + + public void setBootType(String bootType) { + this.bootType = bootType; + } } diff --git a/api/src/main/java/org/apache/cloudstack/vm/UnmanagedInstanceTO.java b/api/src/main/java/org/apache/cloudstack/vm/UnmanagedInstanceTO.java index 3d5646f68c9..bba97dff71c 100644 --- a/api/src/main/java/org/apache/cloudstack/vm/UnmanagedInstanceTO.java +++ b/api/src/main/java/org/apache/cloudstack/vm/UnmanagedInstanceTO.java @@ -61,6 +61,9 @@ public class UnmanagedInstanceTO { private String vncPassword; + private String bootType; + private String bootMode; + public String getName() { return name; } @@ -196,6 +199,22 @@ public class UnmanagedInstanceTO { this, "name", "internalCSName", "hostName", "clusterName")); } + public String getBootType() { + return bootType; + } + + public void setBootType(String bootType) { + this.bootType = bootType; + } + + public String getBootMode() { + return bootMode; + } + + public void setBootMode(String bootMode) { + this.bootMode = bootMode; + } + public static class Disk { private String diskId; diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 15e3110f51b..f1a69b6381f 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -61,7 +61,11 @@ import org.apache.cloudstack.ca.CAManager; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.framework.ca.Certificate; import org.apache.cloudstack.framework.config.ConfigKey; @@ -411,6 +415,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VmWorkJobDao vmWorkJobDao; private SingleCache> vmIdsInProgressCache; + DataStoreProviderManager dataStoreProviderManager; VmWorkJobHandlerProxy _jobHandlerProxy = new VmWorkJobHandlerProxy(this); @@ -1224,6 +1229,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac planChangedByVolume = true; } } + DataStoreProvider storeProvider = dataStoreProviderManager.getDataStoreProvider(pool.getStorageProviderName()); + DataStoreDriver storeDriver = storeProvider.getDataStoreDriver(); + if (storeDriver instanceof PrimaryDataStoreDriver) { + ((PrimaryDataStoreDriver)storeDriver).detachVolumeFromAllStorageNodes(vol); + } } } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index 730b737e0f4..f83a6c1d4e5 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -43,6 +43,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import javax.persistence.EntityExistsException; +import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; import com.cloud.hypervisor.vmware.util.VmwareClient; import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; import org.apache.cloudstack.api.command.admin.zone.ImportVsphereStoragePoliciesCmd; @@ -171,8 +172,11 @@ import com.cloud.vm.dao.VMInstanceDao; import com.vmware.pbm.PbmProfile; import com.vmware.vim25.AboutInfo; import com.vmware.vim25.ManagedObjectReference; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class VmwareManagerImpl extends ManagerBase implements VmwareManager, VmwareStorageMount, Listener, VmwareDatacenterService, Configurable { + protected static Logger static_logger = LogManager.getLogger(VmwareManagerImpl.class); private static final long SECONDS_PER_MINUTE = 60; private static final int DEFAULT_PORTS_PER_DV_PORT_GROUP_VSPHERE4_x = 256; @@ -1585,14 +1589,26 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw return compatiblePools; } - @Override - public List listVMsInDatacenter(ListVmwareDcVmsCmd cmd) { + private static class VcenterData { + public final String vcenter; + public final String datacenterName; + public final String username; + public final String password; + + public VcenterData(String vcenter, String datacenterName, String username, String password) { + this.vcenter = vcenter; + this.datacenterName = datacenterName; + this.username = username; + this.password = password; + } + } + + private VcenterData getVcenterData(ListVmwareDcVmsCmd cmd) { String vcenter = cmd.getVcenter(); String datacenterName = cmd.getDatacenterName(); String username = cmd.getUsername(); String password = cmd.getPassword(); Long existingVcenterId = cmd.getExistingVcenterId(); - String keyword = cmd.getKeyword(); if ((existingVcenterId == null && StringUtils.isBlank(vcenter)) || (existingVcenterId != null && StringUtils.isNotBlank(vcenter))) { @@ -1613,34 +1629,69 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw username = vmwareDc.getUser(); password = vmwareDc.getPassword(); } + VcenterData vmwaredc = new VcenterData(vcenter, datacenterName, username, password); + return vmwaredc; + } + + private static VmwareContext getVmwareContext(String vcenter, String username, String password) throws Exception { + static_logger.debug(String.format("Connecting to the VMware vCenter %s", vcenter)); + String serviceUrl = String.format("https://%s/sdk/vimService", vcenter); + VmwareClient vimClient = new VmwareClient(vcenter); + vimClient.connect(serviceUrl, username, password); + return new VmwareContext(vimClient, vcenter); + } + + @Override + public List listVMsInDatacenter(ListVmwareDcVmsCmd cmd) { + VcenterData vmwareDC = getVcenterData(cmd); + String vcenter = vmwareDC.vcenter; + String username = vmwareDC.username; + String password = vmwareDC.password; + String datacenterName = vmwareDC.datacenterName; + String keyword = cmd.getKeyword(); + String esxiHostName = cmd.getHostName(); + String virtualMachineName = cmd.getInstanceName(); try { logger.debug(String.format("Connecting to the VMware datacenter %s at vCenter %s to retrieve VMs", datacenterName, vcenter)); - String serviceUrl = String.format("https://%s/sdk/vimService", vcenter); - VmwareClient vimClient = new VmwareClient(vcenter); - vimClient.connect(serviceUrl, username, password); - VmwareContext context = new VmwareContext(vimClient, vcenter); + VmwareContext context = getVmwareContext(vcenter, username, password); + DatacenterMO dcMo = getDatacenterMO(context, vcenter, datacenterName); - DatacenterMO dcMo = new DatacenterMO(context, datacenterName); - ManagedObjectReference dcMor = dcMo.getMor(); - if (dcMor == null) { - String msg = String.format("Unable to find VMware datacenter %s in vCenter %s", - datacenterName, vcenter); - logger.error(msg); - throw new InvalidParameterValueException(msg); + List instances; + if (StringUtils.isNotBlank(esxiHostName) && StringUtils.isNotBlank(virtualMachineName)) { + ManagedObjectReference hostMor = dcMo.findHost(esxiHostName); + if (hostMor == null) { + String errorMsg = String.format("Cannot find a host with name %s on vcenter %s", esxiHostName, vcenter); + logger.error(errorMsg); + throw new CloudRuntimeException(errorMsg); + } + HostMO hostMO = new HostMO(context, hostMor); + VirtualMachineMO vmMo = hostMO.findVmOnHyperHost(virtualMachineName); + instances = Collections.singletonList(VmwareHelper.getUnmanagedInstance(hostMO, vmMo)); + } else { + instances = dcMo.getAllVmsOnDatacenter(keyword); } - List instances = dcMo.getAllVmsOnDatacenter(); - return StringUtils.isBlank(keyword) ? instances : - instances.stream().filter(x -> x.getName().toLowerCase().contains(keyword.toLowerCase())).collect(Collectors.toList()); + return instances; } catch (Exception e) { - String errorMsg = String.format("Error retrieving stopped VMs from the VMware VC %s datacenter %s: %s", + String errorMsg = String.format("Error retrieving VMs from the VMware VC %s datacenter %s: %s", vcenter, datacenterName, e.getMessage()); logger.error(errorMsg, e); throw new CloudRuntimeException(errorMsg); } } + private static DatacenterMO getDatacenterMO(VmwareContext context, String vcenter, String datacenterName) throws Exception { + DatacenterMO dcMo = new DatacenterMO(context, datacenterName); + ManagedObjectReference dcMor = dcMo.getMor(); + if (dcMor == null) { + String msg = String.format("Unable to find VMware datacenter %s in vCenter %s", datacenterName, vcenter); + static_logger.error(msg); + throw new InvalidParameterValueException(msg); + } + return dcMo; + } + @Override public boolean hasNexusVSM(Long clusterId) { ClusterVSMMapVO vsmMapVo = null; @@ -1693,7 +1744,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw } /** - * This task is to cleanup templates from primary storage that are otherwise not cleaned by the {@link com.cloud.storage.StorageManagerImpl.StorageGarbageCollector}. + * This task is to cleanup templates from primary storage that are otherwise not cleaned by the {code}StorageGarbageCollector{code} from {@link com.cloud.storage.StorageManagerImpl}. * it is called at regular intervals when storage.template.cleanup.enabled == true * It collect all templates that * - are deleted from cloudstack diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcVmsCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcVmsCmd.java index 4dd1b4beb09..3c7b233f7c9 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcVmsCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcVmsCmd.java @@ -70,6 +70,12 @@ public class ListVmwareDcVmsCmd extends BaseListCmd { @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "The password for specified username.") private String password; + @Parameter(name = ApiConstants.HOST_NAME, type = CommandType.STRING, description = "Name of the host on vCenter. Must be set along with the instancename parameter") + private String hostName; + + @Parameter(name = ApiConstants.INSTANCE_NAME, type = CommandType.STRING, description = "Name of the VM on vCenter. Must be set along with the hostname parameter") + private String instanceName; + public String getVcenter() { return vcenter; } @@ -86,10 +92,18 @@ public class ListVmwareDcVmsCmd extends BaseListCmd { return datacenterName; } + public String getHostName() { + return hostName; + } + public Long getExistingVcenterId() { return existingVcenterId; } + public String getInstanceName() { + return instanceName; + } + @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { checkParameters(); @@ -125,6 +139,11 @@ public class ListVmwareDcVmsCmd extends BaseListCmd { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please set all the information for a vCenter IP/Name, datacenter, username and password"); } + if ((StringUtils.isNotBlank(instanceName) && StringUtils.isBlank(hostName)) || + (StringUtils.isBlank(instanceName) && StringUtils.isNotBlank(hostName))) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, + "Please set the hostname parameter along with the instancename parameter"); + } } @Override diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index a193726eb64..3331053dff2 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -5267,6 +5267,8 @@ public class ApiResponseHelper implements ResponseGenerator { response.setMemory(instance.getMemory()); response.setOperatingSystemId(instance.getOperatingSystemId()); response.setOperatingSystem(instance.getOperatingSystem()); + response.setBootMode(instance.getBootMode()); + response.setBootType(instance.getBootType()); response.setObjectName("unmanagedinstance"); if (instance.getDisks() != null) { diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index a0c367ad72e..db577392fde 100644 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -4554,14 +4554,24 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati String endIP = cmd.getEndIp(); final String newVlanGateway = cmd.getGateway(); final String newVlanNetmask = cmd.getNetmask(); + Long networkId = cmd.getNetworkID(); + Long physicalNetworkId = cmd.getPhysicalNetworkId(); + + // Verify that network exists + Network network = getNetwork(networkId); + if (network != null) { + zoneId = network.getDataCenterId(); + physicalNetworkId = network.getPhysicalNetworkId(); + } + String vlanId = cmd.getVlan(); + vlanId = verifyAndUpdateVlanId(vlanId, network); + // TODO decide if we should be forgiving or demand a valid and complete URI if (!(vlanId == null || "".equals(vlanId) || vlanId.startsWith(BroadcastDomainType.Vlan.scheme()))) { vlanId = BroadcastDomainType.Vlan.toUri(vlanId).toString(); } final Boolean forVirtualNetwork = cmd.isForVirtualNetwork(); - Long networkId = cmd.getNetworkID(); - Long physicalNetworkId = cmd.getPhysicalNetworkId(); final String accountName = cmd.getAccountName(); final Long projectId = cmd.getProjectId(); final Long domainId = cmd.getDomainId(); @@ -4634,18 +4644,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } - // Verify that network exists - Network network = null; - if (networkId != null) { - network = _networkDao.findById(networkId); - if (network == null) { - throw new InvalidParameterValueException("Unable to find network by id " + networkId); - } else { - zoneId = network.getDataCenterId(); - physicalNetworkId = network.getPhysicalNetworkId(); - } - } - // Verify that zone exists final DataCenterVO zone = _zoneDao.findById(zoneId); if (zone == null) { @@ -4784,6 +4782,32 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati ip6Cidr, domain, vlanOwner, network, sameSubnet, cmd.isForNsx()); } + private Network getNetwork(Long networkId) { + if (networkId == null) { + return null; + } + + Network network = _networkDao.findById(networkId); + if (network == null) { + throw new InvalidParameterValueException("Unable to find network by id " + networkId); + } + + return network; + } + + private String verifyAndUpdateVlanId(String vlanId, Network network) { + if (!StringUtils.isBlank(vlanId)) { + return vlanId; + } + + if (network == null || network.getTrafficType() != TrafficType.Guest) { + return Vlan.UNTAGGED; + } + + boolean connectivityWithoutVlan = isConnectivityWithoutVlan(network); + return getNetworkVlanId(network, connectivityWithoutVlan); + } + private Vlan commitVlan(final Long zoneId, final Long podId, final String startIP, final String endIP, final String newVlanGatewayFinal, final String newVlanNetmaskFinal, final String vlanId, final Boolean forVirtualNetwork, final Boolean forSystemVms, final Long networkId, final Long physicalNetworkId, final String startIPv6, final String endIPv6, final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair> sameSubnet, boolean forNsx) { @@ -4992,28 +5016,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // same as network's vlan // 2) if vlan is missing, default it to the guest network's vlan if (network.getTrafficType() == TrafficType.Guest) { - String networkVlanId = null; - boolean connectivityWithoutVlan = false; - if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Connectivity)) { - Map connectivityCapabilities = _networkModel.getNetworkServiceCapabilities(network.getId(), Service.Connectivity); - connectivityWithoutVlan = MapUtils.isNotEmpty(connectivityCapabilities) && connectivityCapabilities.containsKey(Capability.NoVlan); - } - - final URI uri = network.getBroadcastUri(); - if (connectivityWithoutVlan) { - networkVlanId = network.getBroadcastDomainType().toUri(network.getUuid()).toString(); - } else if (uri != null) { - // Do not search for the VLAN tag when the network doesn't support VLAN - if (uri.toString().startsWith("vlan")) { - final String[] vlan = uri.toString().split("vlan:\\/\\/"); - networkVlanId = vlan[1]; - // For pvlan - if (network.getBroadcastDomainType() != BroadcastDomainType.Vlan) { - networkVlanId = networkVlanId.split("-")[0]; - } - } - } - + boolean connectivityWithoutVlan = isConnectivityWithoutVlan(network); + String networkVlanId = getNetworkVlanId(network, connectivityWithoutVlan); if (vlanId != null && !connectivityWithoutVlan) { // if vlan is specified, throw an error if it's not equal to // network's vlanId @@ -5145,6 +5149,36 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return vlan; } + private boolean isConnectivityWithoutVlan(Network network) { + boolean connectivityWithoutVlan = false; + if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Connectivity)) { + Map connectivityCapabilities = _networkModel.getNetworkServiceCapabilities(network.getId(), Service.Connectivity); + connectivityWithoutVlan = MapUtils.isNotEmpty(connectivityCapabilities) && connectivityCapabilities.containsKey(Capability.NoVlan); + } + return connectivityWithoutVlan; + } + + private String getNetworkVlanId(Network network, boolean connectivityWithoutVlan) { + String networkVlanId = null; + if (connectivityWithoutVlan) { + return network.getBroadcastDomainType().toUri(network.getUuid()).toString(); + } + + final URI uri = network.getBroadcastUri(); + if (uri != null) { + // Do not search for the VLAN tag when the network doesn't support VLAN + if (uri.toString().startsWith("vlan")) { + final String[] vlan = uri.toString().split("vlan:\\/\\/"); + networkVlanId = vlan[1]; + // For pvlan + if (network.getBroadcastDomainType() != BroadcastDomainType.Vlan) { + networkVlanId = networkVlanId.split("-")[0]; + } + } + } + return networkVlanId; + } + private void checkZoneVlanIpOverlap(DataCenterVO zone, Network network, String newCidr, String vlanId, String vlanGateway, String vlanNetmask, String startIP, String endIP) { // Throw an exception if this subnet overlaps with subnet on other VLAN, // if this is ip range extension, gateway, network mask should be same and ip range should not overlap diff --git a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 572e0ace723..7fa767fe885 100755 --- a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -918,7 +918,7 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement } else if (intervalTypeStr != null && volumeId != null) { Type type = SnapshotVO.getSnapshotType(intervalTypeStr); if (type == null) { - throw new InvalidParameterValueException("Unsupported snapstho interval type " + intervalTypeStr); + throw new InvalidParameterValueException("Unsupported snapshot interval type " + intervalTypeStr); } sc.setParameters("snapshotTypeEQ", type.ordinal()); } else { diff --git a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java index d64a42efbec..c46f1f43fd0 100644 --- a/server/src/main/java/com/cloud/usage/UsageServiceImpl.java +++ b/server/src/main/java/com/cloud/usage/UsageServiceImpl.java @@ -26,8 +26,6 @@ import java.util.TimeZone; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.domain.Domain; -import com.cloud.utils.DateUtil; import org.apache.cloudstack.api.command.admin.usage.GenerateUsageRecordsCmd; import org.apache.cloudstack.api.command.admin.usage.ListUsageRecordsCmd; import org.apache.cloudstack.api.command.admin.usage.RemoveRawUsageRecordsCmd; @@ -42,6 +40,7 @@ import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; import com.cloud.configuration.Config; +import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.exception.InvalidParameterValueException; @@ -58,6 +57,8 @@ import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.security.SecurityGroupVO; import com.cloud.network.security.dao.SecurityGroupDao; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; import com.cloud.storage.SnapshotVO; @@ -72,6 +73,7 @@ import com.cloud.user.Account; import com.cloud.user.AccountService; import com.cloud.user.AccountVO; import com.cloud.user.dao.AccountDao; +import com.cloud.utils.DateUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; @@ -121,6 +123,8 @@ public class UsageServiceImpl extends ManagerBase implements UsageService, Manag private IPAddressDao _ipDao; @Inject private HostDao _hostDao; + @Inject + private NetworkOfferingDao _networkOfferingDao; public UsageServiceImpl() { } @@ -245,6 +249,7 @@ public class UsageServiceImpl extends ManagerBase implements UsageService, Manag } Long usageDbId = null; + boolean offeringExistsForNetworkOfferingType = false; switch (usageType.intValue()) { case UsageTypes.NETWORK_BYTES_RECEIVED: @@ -318,13 +323,19 @@ public class UsageServiceImpl extends ManagerBase implements UsageService, Manag usageDbId = ip.getId(); } break; + case UsageTypes.NETWORK_OFFERING: + NetworkOfferingVO networkOffering = _networkOfferingDao.findByUuidIncludingRemoved(usageId); + if (networkOffering != null) { + offeringExistsForNetworkOfferingType = true; + sc.addAnd("offeringId", SearchCriteria.Op.EQ, networkOffering.getId()); + } default: break; } if (usageDbId != null) { sc.addAnd("usageId", SearchCriteria.Op.EQ, usageDbId); - } else { + } else if (!offeringExistsForNetworkOfferingType) { // return an empty list if usageId was not found return new Pair, Integer>(new ArrayList(), new Integer(0)); } diff --git a/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java b/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java index c2c78402aa1..b10a94c0784 100644 --- a/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java +++ b/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java @@ -55,6 +55,8 @@ import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.offering.DiskOffering; @@ -196,6 +198,8 @@ public class ConfigurationManagerTest { @Mock HostPodDao _podDao; @Mock + NetworkDao _networkDao; + @Mock PhysicalNetworkDao _physicalNetworkDao; @Mock ImageStoreDao _imageStoreDao; @@ -1331,6 +1335,8 @@ public class ConfigurationManagerTest { public void testWrongIpv6CreateVlanAndPublicIpRange() { CreateVlanIpRangeCmd cmd = Mockito.mock(CreateVlanIpRangeCmd.class); Mockito.when(cmd.getIp6Cidr()).thenReturn("fd17:5:8a43:e2a4:c000::/66"); + NetworkVO network = Mockito.mock(NetworkVO.class); + Mockito.when(_networkDao.findById(Mockito.anyLong())).thenReturn(network); try { configurationMgr.createVlanAndPublicIpRange(cmd); } catch (InsufficientCapacityException | ResourceUnavailableException | ResourceAllocationException e) { diff --git a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index 04f9c476d47..25d43388b65 100644 --- a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -1089,6 +1089,12 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar try { _itMgr.expunge(ssvm.getUuid()); + ssvm.setPublicIpAddress(null); + ssvm.setPublicMacAddress(null); + ssvm.setPublicNetmask(null); + ssvm.setPrivateMacAddress(null); + ssvm.setPrivateIpAddress(null); + _secStorageVmDao.update(ssvm.getId(), ssvm); _secStorageVmDao.remove(ssvm.getId()); HostVO host = _hostDao.findByTypeNameAndZoneId(ssvm.getDataCenterId(), ssvm.getHostName(), Host.Type.SecondaryStorageVM); if (host != null) { @@ -1373,7 +1379,7 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar @Override public void finalizeExpunge(VirtualMachine vm) { SecondaryStorageVmVO ssvm = _secStorageVmDao.findByUuid(vm.getUuid()); - + ssvm.setPrivateMacAddress(null); ssvm.setPublicIpAddress(null); ssvm.setPublicMacAddress(null); ssvm.setPublicNetmask(null); diff --git a/ui/.env.qa b/ui/.env.qa new file mode 100644 index 00000000000..d32df4035d7 --- /dev/null +++ b/ui/.env.qa @@ -0,0 +1 @@ +CS_URL=https://qa.cloudstack.cloud/simulator/pr/10580 diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index e61e5ee4a6e..027bbbd123f 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -2086,6 +2086,7 @@ "label.sharewith": "Share with", "label.showing": "Showing", "label.show.usage.records": "Show usage records", +"label.showing.results.for": "Showing results for \"%x\"", "label.shrinkok": "Shrink OK", "label.shutdown": "Shutdown", "label.shutdown.provider": "Shutdown provider", diff --git a/ui/src/components/header/ProjectMenu.vue b/ui/src/components/header/ProjectMenu.vue index 6fb0c3af350..590a8a2fbd0 100644 --- a/ui/src/components/header/ProjectMenu.vue +++ b/ui/src/components/header/ProjectMenu.vue @@ -17,112 +17,75 @@ diff --git a/ui/src/components/widgets/InfiniteScrollSelect.vue b/ui/src/components/widgets/InfiniteScrollSelect.vue new file mode 100644 index 00000000000..f97faf390f8 --- /dev/null +++ b/ui/src/components/widgets/InfiniteScrollSelect.vue @@ -0,0 +1,298 @@ +// 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. + + + + + + diff --git a/ui/src/views/compute/EditVM.vue b/ui/src/views/compute/EditVM.vue index fad1dcc254e..834e11c3773 100644 --- a/ui/src/views/compute/EditVM.vue +++ b/ui/src/views/compute/EditVM.vue @@ -202,7 +202,7 @@ export default { }, fetchZoneDetails () { api('listZones', { - zoneid: this.resource.zoneid + id: this.resource.zoneid }).then(response => { const zone = response?.listzonesresponse?.zone || [] this.securityGroupsEnabled = zone?.[0]?.securitygroupsenabled || this.$store.getters.showSecurityGroups @@ -336,10 +336,8 @@ export default { params.name = values.name params.displayname = values.displayname params.ostypeid = values.ostypeid - if (this.securityGroupsEnabled) { - if (values.securitygroupids) { - params.securitygroupids = values.securitygroupids - } + if (this.securityGroupsEnabled && Array.isArray(values.securitygroupids) && values.securitygroupids.length > 0) { + params.securitygroupids = values.securitygroupids } if (values.isdynamicallyscalable !== undefined) { params.isdynamicallyscalable = values.isdynamicallyscalable diff --git a/ui/src/views/network/CreateNetworkPermission.vue b/ui/src/views/network/CreateNetworkPermission.vue index 037e91eb9fd..6d73bb07ca3 100644 --- a/ui/src/views/network/CreateNetworkPermission.vue +++ b/ui/src/views/network/CreateNetworkPermission.vue @@ -29,47 +29,27 @@ - - - - - - {{ opt.name || opt.description }} - - - + api="listAccounts" + :apiParams="accountsApiParams" + resourceType="account" + defaultIcon="team-outlined" /> - - - - - - {{ opt.name || opt.description }} - - - + api="listProjects" + :apiParams="projectsApiParams" + resourceType="project" + defaultIcon="project-outlined" />