diff --git a/api/src/main/java/com/cloud/vm/VmDetailConstants.java b/api/src/main/java/com/cloud/vm/VmDetailConstants.java index 603948d76cf..29803d5271b 100644 --- a/api/src/main/java/com/cloud/vm/VmDetailConstants.java +++ b/api/src/main/java/com/cloud/vm/VmDetailConstants.java @@ -74,6 +74,7 @@ public interface VmDetailConstants { String ENCRYPTED_PASSWORD = "Encrypted.Password"; String CONFIG_DRIVE_LOCATION = "configDriveLocation"; + String LAST_CONFIG_DRIVE_LOCATION = "lastConfigDriveLocation"; String SKIP_DRS = "skipFromDRS"; diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentAttache.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentAttache.java index 173fd9fc704..c0f7586aee0 100644 --- a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentAttache.java +++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentAttache.java @@ -47,6 +47,7 @@ import com.cloud.agent.api.CleanupNetworkRulesCmd; import com.cloud.agent.api.Command; import com.cloud.agent.api.CreateStoragePoolCommand; import com.cloud.agent.api.DeleteStoragePoolCommand; +import com.cloud.agent.api.HandleConfigDriveIsoCommand; import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.MigrateCommand; import com.cloud.agent.api.ModifySshKeysCommand; @@ -122,11 +123,10 @@ public abstract class AgentAttache { public final static String[] s_commandsAllowedInMaintenanceMode = new String[] { MaintainCommand.class.toString(), MigrateCommand.class.toString(), StopCommand.class.toString(), CheckVirtualMachineCommand.class.toString(), PingTestCommand.class.toString(), CheckHealthCommand.class.toString(), - ReadyCommand.class.toString(), ShutdownCommand.class.toString(), SetupCommand.class.toString(), - CleanupNetworkRulesCmd.class.toString(), CheckNetworkCommand.class.toString(), PvlanSetupCommand.class.toString(), CheckOnHostCommand.class.toString(), - ModifyTargetsCommand.class.toString(), ModifySshKeysCommand.class.toString(), - CreateStoragePoolCommand.class.toString(), DeleteStoragePoolCommand.class.toString(), ModifyStoragePoolCommand.class.toString(), - SetupMSListCommand.class.toString(), RollingMaintenanceCommand.class.toString(), CleanupPersistentNetworkResourceCommand.class.toString()}; + ReadyCommand.class.toString(), ShutdownCommand.class.toString(), SetupCommand.class.toString(), CleanupNetworkRulesCmd.class.toString(), + CheckNetworkCommand.class.toString(), PvlanSetupCommand.class.toString(), CheckOnHostCommand.class.toString(), ModifyTargetsCommand.class.toString(), + ModifySshKeysCommand.class.toString(), CreateStoragePoolCommand.class.toString(), DeleteStoragePoolCommand.class.toString(), ModifyStoragePoolCommand.class.toString(), + SetupMSListCommand.class.toString(), RollingMaintenanceCommand.class.toString(), CleanupPersistentNetworkResourceCommand.class.toString(), HandleConfigDriveIsoCommand.class.toString()}; protected final static String[] s_commandsNotAllowedInConnectingMode = new String[] { StartCommand.class.toString(), CreateCommand.class.toString() }; static { Arrays.sort(s_commandsAllowedInMaintenanceMode); diff --git a/packaging/el8/cloud.spec b/packaging/el8/cloud.spec index f9d6fd1ce87..eb03cfe0df4 100644 --- a/packaging/el8/cloud.spec +++ b/packaging/el8/cloud.spec @@ -245,6 +245,7 @@ mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/lib mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/setup mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/management mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management +mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/systemd/system/%{name}-management.service.d mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/run mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/setup/wheel @@ -294,6 +295,7 @@ install -D utils/target/cloud-utils-%{_maventag}-bundled.jar ${RPM_BUILD_ROOT}%{ install -D packaging/el8/cloud-ipallocator.rc ${RPM_BUILD_ROOT}%{_initrddir}/%{name}-ipallocator install -D packaging/el8/cloud.limits ${RPM_BUILD_ROOT}%{_sysconfdir}/security/limits.d/cloud +install -D packaging/el8/filelimit.conf ${RPM_BUILD_ROOT}%{_sysconfdir}/systemd/system/%{name}-management.service.d install -D packaging/systemd/cloudstack-management.service ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-management.service install -D packaging/systemd/cloudstack-management.default ${RPM_BUILD_ROOT}%{_sysconfdir}/default/%{name}-management install -D server/target/conf/cloudstack-sudoers ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management @@ -575,6 +577,7 @@ pip3 install --upgrade /usr/share/cloudstack-marvin/Marvin-*.tar.gz %config(noreplace) %{_sysconfdir}/default/%{name}-management %config(noreplace) %{_sysconfdir}/sudoers.d/%{name}-management %config(noreplace) %{_sysconfdir}/security/limits.d/cloud +%config(noreplace) %{_sysconfdir}/systemd/system/%{name}-management.service.d %config(noreplace) %attr(0640,root,cloud) %{_sysconfdir}/%{name}/management/db.properties %config(noreplace) %attr(0640,root,cloud) %{_sysconfdir}/%{name}/management/server.properties %config(noreplace) %attr(0640,root,cloud) %{_sysconfdir}/%{name}/management/config.json diff --git a/packaging/el8/filelimit.conf b/packaging/el8/filelimit.conf new file mode 100644 index 00000000000..7a8a835e3fe --- /dev/null +++ b/packaging/el8/filelimit.conf @@ -0,0 +1,20 @@ +# 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. + +# should go in /etc/systemd/system/cloudstack-management.service.d/ +[Service] +LimitNPROC=infinity diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 7374d46edd6..ca3395be5dc 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -1031,7 +1031,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv hostHealthCheckScriptPath = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.HEALTH_CHECK_SCRIPT_PATH); if (StringUtils.isNotBlank(hostHealthCheckScriptPath) && !new File(hostHealthCheckScriptPath).exists()) { - logger.info(String.format("Unable to find the host health check script at: %s, " + + LOGGER.info(String.format("Unable to find the host health check script at: %s, " + "discarding it", hostHealthCheckScriptPath)); } @@ -2796,11 +2796,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv if (hostCpuMaxCapacity > 0) { int updatedCpuShares = (int) Math.ceil((requestedCpuShares * CGROUP_V2_UPPER_LIMIT) / (double) hostCpuMaxCapacity); - logger.debug(String.format("This host utilizes cgroupv2 (as the max shares value is [%s]), thus, the VM requested shares of [%s] will be converted to " + + LOGGER.debug(String.format("This host utilizes cgroupv2 (as the max shares value is [%s]), thus, the VM requested shares of [%s] will be converted to " + "consider the host limits; the new CPU shares value is [%s].", hostCpuMaxCapacity, requestedCpuShares, updatedCpuShares)); return updatedCpuShares; } - logger.debug(String.format("This host does not have a maximum CPU shares set; therefore, this host utilizes cgroupv1 and the VM requested CPU shares [%s] will not be " + + LOGGER.debug(String.format("This host does not have a maximum CPU shares set; therefore, this host utilizes cgroupv1 and the VM requested CPU shares [%s] will not be " + "converted.", requestedCpuShares)); return requestedCpuShares; } @@ -2931,7 +2931,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv LOGGER.warn(String.format("Setting System VM's [%s] current memory as max memory [%s].", vmTO.toString(), maxRam)); } else { long minRam = ByteScaleUtils.bytesToKibibytes(vmTO.getMinRam()); - logger.debug(String.format("Setting VM's [%s] current memory as min memory [%s] due to memory ballooning is enabled.", vmTO.toString(), minRam)); + LOGGER.debug(String.format("Setting VM's [%s] current memory as min memory [%s] due to memory ballooning is enabled.", vmTO.toString(), minRam)); retVal = minRam; } return retVal; @@ -3002,9 +3002,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv public static boolean useBLOCKDiskType(KVMPhysicalDisk physicalDisk) { return physicalDisk != null && - physicalDisk.getPool().getType() == StoragePoolType.Linstor && + physicalDisk.getPool() != null && + StoragePoolType.Linstor.equals(physicalDisk.getPool().getType()) && physicalDisk.getFormat() != null && - physicalDisk.getFormat()== PhysicalDiskFormat.RAW; + PhysicalDiskFormat.RAW.equals(physicalDisk.getFormat()); } public static DiskDef.DiskType getDiskType(KVMPhysicalDisk physicalDisk) { @@ -3283,7 +3284,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv * (ii) Libvirt >= 6.3.0 */ public void setDiskIoDriver(DiskDef disk, IoDriverPolicy ioDriver) { - logger.debug(String.format("Disk IO driver policy [%s]. The host supports the io_uring policy [%s]", ioDriver, enableIoUring)); + LOGGER.debug(String.format("Disk IO driver policy [%s]. The host supports the io_uring policy [%s]", ioDriver, enableIoUring)); if (ioDriver != null) { if (IoDriverPolicy.IO_URING != ioDriver) { disk.setIoDriver(ioDriver); @@ -3426,13 +3427,15 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } if (configdrive != null) { try { + LOGGER.debug(String.format("Detaching ConfigDrive ISO of the VM %s, at path %s", vmName, configdrive.getDiskPath())); String result = attachOrDetachISO(conn, vmName, configdrive.getDiskPath(), false, CONFIG_DRIVE_ISO_DEVICE_ID); if (result != null) { - LOGGER.warn("Detach ConfigDrive ISO with result: " + result); + LOGGER.warn("Detach ConfigDrive ISO of the VM {}, at path {} with result: {}", vmName, configdrive.getDiskPath(), result); } + LOGGER.debug(String.format("Attaching ConfigDrive ISO of the VM %s, at path %s", vmName, configdrive.getDiskPath())); result = attachOrDetachISO(conn, vmName, configdrive.getDiskPath(), true, CONFIG_DRIVE_ISO_DEVICE_ID); if (result != null) { - LOGGER.warn("Attach ConfigDrive ISO with result: " + result); + LOGGER.warn("Attach ConfigDrive ISO of the VM {}, at path {} with result: {}", vmName, configdrive.getDiskPath(), result); } } catch (final LibvirtException | InternalErrorException | URISyntaxException e) { final String msg = "Detach and attach ConfigDrive ISO failed due to " + e.toString(); @@ -3444,16 +3447,20 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv public synchronized String attachOrDetachISO(final Connect conn, final String vmName, String isoPath, final boolean isAttach, final Integer diskSeq) throws LibvirtException, URISyntaxException, InternalErrorException { final DiskDef iso = new DiskDef(); - if (isoPath != null && isAttach) { - final int index = isoPath.lastIndexOf("/"); - final String path = isoPath.substring(0, index); - final String name = isoPath.substring(index + 1); - final KVMStoragePool secondaryPool = storagePoolManager.getStoragePoolByURI(path); - final KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name); - final DiskDef.DiskType diskType = getDiskType(isoVol); - isoPath = isoVol.getPath(); + if (isAttach && StringUtils.isNotBlank(isoPath) && isoPath.lastIndexOf("/") > 0) { + if (isoPath.startsWith(getConfigPath() + "/" + ConfigDrive.CONFIGDRIVEDIR) && isoPath.contains(vmName)) { + iso.defISODisk(isoPath, diskSeq, DiskDef.DiskType.FILE); + } else { + final int index = isoPath.lastIndexOf("/"); + final String path = isoPath.substring(0, index); + final String name = isoPath.substring(index + 1); + final KVMStoragePool storagePool = storagePoolManager.getStoragePoolByURI(path); + final KVMPhysicalDisk isoVol = storagePool.getPhysicalDisk(name); + final DiskDef.DiskType diskType = getDiskType(isoVol); + isoPath = isoVol.getPath(); - iso.defISODisk(isoPath, diskSeq, diskType); + iso.defISODisk(isoPath, diskSeq, diskType); + } } else { iso.defISODisk(null, diskSeq, DiskDef.DiskType.FILE); } @@ -3640,19 +3647,19 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv */ private HealthCheckResult getHostHealthCheckResult() { if (StringUtils.isBlank(hostHealthCheckScriptPath)) { - logger.debug("Host health check script path is not specified"); + LOGGER.debug("Host health check script path is not specified"); return HealthCheckResult.IGNORE; } File script = new File(hostHealthCheckScriptPath); if (!script.exists() || !script.isFile() || !script.canExecute()) { - logger.warn(String.format("The host health check script file set at: %s cannot be executed, " + + LOGGER.warn(String.format("The host health check script file set at: %s cannot be executed, " + "reason: %s", hostHealthCheckScriptPath, !script.exists() ? "file does not exist" : "please check file permissions to execute this file")); return HealthCheckResult.IGNORE; } int exitCode = executeBashScriptAndRetrieveExitValue(hostHealthCheckScriptPath); - if (logger.isDebugEnabled()) { - logger.debug(String.format("Host health check script exit code: %s", exitCode)); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(String.format("Host health check script exit code: %s", exitCode)); } return retrieveHealthCheckResultFromExitCode(exitCode); } @@ -3761,17 +3768,17 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv */ protected void calculateHostCpuMaxCapacity(int cpuCores, Long cpuSpeed) { String output = Script.runSimpleBashScript(COMMAND_GET_CGROUP_HOST_VERSION); - logger.info(String.format("Host uses control group [%s].", output)); + LOGGER.info(String.format("Host uses control group [%s].", output)); if (!CGROUP_V2.equals(output)) { - logger.info(String.format("Setting host CPU max capacity to 0, as it uses cgroup v1.", getHostCpuMaxCapacity())); + LOGGER.info(String.format("Setting host CPU max capacity to 0, as it uses cgroup v1.", getHostCpuMaxCapacity())); setHostCpuMaxCapacity(0); return; } - logger.info(String.format("Calculating the max shares of the host.")); + LOGGER.info(String.format("Calculating the max shares of the host.")); setHostCpuMaxCapacity(cpuCores * cpuSpeed.intValue()); - logger.info(String.format("The max shares of the host is [%d].", getHostCpuMaxCapacity())); + LOGGER.info(String.format("The max shares of the host is [%d].", getHostCpuMaxCapacity())); } private StartupStorageCommand createLocalStoragePool(String localStoragePath, String localStorageUUID, StartupRoutingCommand cmd) { @@ -3834,7 +3841,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv String sourcePath = null; try { String mountResult = Script.runSimpleBashScript("mount | grep \"" + diskPath + "\""); - logger.debug("Got mount result for " + diskPath + "\n\n" + mountResult); + LOGGER.debug("Got mount result for " + diskPath + "\n\n" + mountResult); if (StringUtils.isNotEmpty(mountResult)) { String[] res = mountResult.strip().split(" "); if (res[0].contains(":")) { @@ -3851,7 +3858,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv return new Pair<>(sourceHostIp, sourcePath); } } catch (Exception ex) { - logger.warn("Failed to list source host and IP for " + diskPath + ex.toString()); + LOGGER.warn("Failed to list source host and IP for " + diskPath + ex.toString()); } return null; } @@ -3864,14 +3871,14 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv domainNames.add(names[i]); } } catch (final LibvirtException e) { - logger.warn("Failed to list defined domains", e); + LOGGER.warn("Failed to list defined domains", e); } int[] ids = null; try { ids = conn.listDomains(); } catch (final LibvirtException e) { - logger.warn("Failed to list domains", e); + LOGGER.warn("Failed to list domains", e); return domainNames; } @@ -4959,7 +4966,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv public boolean setupTungstenVRouter(final String oper, final String inf, final String subnet, final String route, final String vrf) { - final Script cmd = new Script(setupTungstenVrouterPath, timeout, logger); + final Script cmd = new Script(setupTungstenVrouterPath, timeout, LOGGER); cmd.add(oper); cmd.add(inf); cmd.add(subnet); @@ -4972,7 +4979,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv public boolean updateTungstenLoadbalancerStats(final String lbUuid, final String lbStatsPort, final String lbStatsUri, final String lbStatsAuth) { - final Script cmd = new Script(updateTungstenLoadbalancerStatsPath, timeout, logger); + final Script cmd = new Script(updateTungstenLoadbalancerStatsPath, timeout, LOGGER); cmd.add(lbUuid); cmd.add(lbStatsPort); cmd.add(lbStatsUri); @@ -4984,7 +4991,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv public boolean updateTungstenLoadbalancerSsl(final String lbUuid, final String sslCertName, final String certificateKey, final String privateKey, final String privateIp, final String port) { - final Script cmd = new Script(updateTungstenLoadbalancerSslPath, timeout, logger); + final Script cmd = new Script(updateTungstenLoadbalancerSslPath, timeout, LOGGER); cmd.add(lbUuid); cmd.add(sslCertName); cmd.add(certificateKey); @@ -4997,7 +5004,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } public boolean setupTfRoute(final String privateIpAddress, final String fromNetwork, final String toNetwork) { - final Script setupTfRouteScript = new Script(routerProxyPath, timeout, logger); + final Script setupTfRouteScript = new Script(routerProxyPath, timeout, LOGGER); setupTfRouteScript.add("setup_tf_route.py"); setupTfRouteScript.add(privateIpAddress); setupTfRouteScript.add(fromNetwork); @@ -5006,7 +5013,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv final OutputInterpreter.OneLineParser setupTfRouteParser = new OutputInterpreter.OneLineParser(); final String result = setupTfRouteScript.execute(setupTfRouteParser); if (result != null) { - logger.debug("Failed to execute setup TF Route:" + result); + LOGGER.debug("Failed to execute setup TF Route:" + result); return false; } return true; @@ -5525,7 +5532,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv interfaceDef.setMultiQueueNumber(nicMultiqueueNumberInteger); } } catch (NumberFormatException ex) { - logger.warn(String.format("VM details %s is not a valid integer value %s", VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber)); + LOGGER.warn(String.format("VM details %s is not a valid integer value %s", VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber)); } } String nicPackedEnabled = details.get(VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED); @@ -5533,7 +5540,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv try { interfaceDef.setPackedVirtQueues(Boolean.valueOf(nicPackedEnabled)); } catch (NumberFormatException ex) { - logger.warn(String.format("VM details %s is not a valid Boolean value %s", VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED, nicPackedEnabled)); + LOGGER.warn(String.format("VM details %s is not a valid Boolean value %s", VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED, nicPackedEnabled)); } } } @@ -5548,11 +5555,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv command.append(remoteFile); command.append(" " + tmpPath); command.append(outputFile); - logger.debug(String.format("Converting remote disk file: %s, output file: %s%s (timeout: %d secs)", remoteFile, tmpPath, outputFile, timeoutInSecs)); + LOGGER.debug(String.format("Converting remote disk file: %s, output file: %s%s (timeout: %d secs)", remoteFile, tmpPath, outputFile, timeoutInSecs)); SshHelper.sshExecute(srcIp, 22, username, null, password, command.toString(), timeoutInSecs * 1000); - logger.debug("Copying converted remote disk file " + outputFile + " to: " + localDir); + LOGGER.debug("Copying converted remote disk file " + outputFile + " to: " + localDir); SshHelper.scpFrom(srcIp, 22, username, null, password, localDir, tmpPath + outputFile); - logger.debug("Successfully copied converted remote disk file to: " + localDir + "/" + outputFile); + LOGGER.debug("Successfully copied converted remote disk file to: " + localDir + "/" + outputFile); return outputFile; } catch (Exception e) { try { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java index 61c20f96bac..0f00a6e29bd 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java @@ -39,6 +39,9 @@ public final class LibvirtGetVmIpAddressCommandWrapper extends CommandWrapper commands = new ArrayList<>(); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java index 53549487704..8d7ee14dc13 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java @@ -118,7 +118,7 @@ public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapp skipDisconnect = true; - if (!storagePoolMgr.connectPhysicalDisksViaVmSpec(vm)) { + if (!storagePoolMgr.connectPhysicalDisksViaVmSpec(vm, true)) { return new PrepareForMigrationAnswer(command, "failed to connect physical disks to host"); } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSetupDirectDownloadCertificateCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSetupDirectDownloadCertificateCommandWrapper.java index fcca16ba618..62cca7eb209 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSetupDirectDownloadCertificateCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSetupDirectDownloadCertificateCommandWrapper.java @@ -36,6 +36,7 @@ import com.cloud.resource.ResourceWrapper; import com.cloud.utils.FileUtil; import com.cloud.utils.PropertiesUtil; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; import com.cloud.utils.script.Script; @ResourceWrapper(handles = SetupDirectDownloadCertificateCommand.class) @@ -131,6 +132,9 @@ public class LibvirtSetupDirectDownloadCertificateCommandWrapper extends Command public Answer execute(SetupDirectDownloadCertificateCommand cmd, LibvirtComputingResource serverResource) { String certificate = cmd.getCertificate(); String certificateName = cmd.getCertificateName(); + if (!NetUtils.verifyDomainNameLabel(certificateName, false)) { + return new Answer(cmd, false, "The provided certificate name is invalid"); + } try { File agentFile = getAgentPropertiesFile(); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java index e0c41acea12..a174c9a6f14 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java @@ -75,7 +75,7 @@ public final class LibvirtStartCommandWrapper extends CommandWrapper details) { + public boolean connectPhysicalDisk(String volumeUuid, KVMStoragePool pool, Map details, boolean isVMMigrate) { // ex. sudo iscsiadm -m node -T iqn.2012-03.com.test:volume1 -p 192.168.233.10:3260 -o new Script iScsiAdmCmd = new Script(true, "iscsiadm", 0, logger); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStoragePool.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStoragePool.java index a89650f6eb6..f5bfd898a4f 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStoragePool.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStoragePool.java @@ -106,7 +106,7 @@ public class IscsiAdmStoragePool implements KVMStoragePool { @Override public boolean connectPhysicalDisk(String name, Map details) { - return this._storageAdaptor.connectPhysicalDisk(name, this, details); + return this._storageAdaptor.connectPhysicalDisk(name, this, details, false); } @Override diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java index 4e76030d06f..e27547acbb2 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java @@ -161,10 +161,10 @@ public class KVMStoragePoolManager { StorageAdaptor adaptor = getStorageAdaptor(type); KVMStoragePool pool = adaptor.getStoragePool(poolUuid); - return adaptor.connectPhysicalDisk(volPath, pool, details); + return adaptor.connectPhysicalDisk(volPath, pool, details, false); } - public boolean connectPhysicalDisksViaVmSpec(VirtualMachineTO vmSpec) { + public boolean connectPhysicalDisksViaVmSpec(VirtualMachineTO vmSpec, boolean isVMMigrate) { boolean result = false; final String vmName = vmSpec.getName(); @@ -187,7 +187,7 @@ public class KVMStoragePoolManager { KVMStoragePool pool = getStoragePool(store.getPoolType(), store.getUuid()); StorageAdaptor adaptor = getStorageAdaptor(pool.getType()); - result = adaptor.connectPhysicalDisk(vol.getPath(), pool, disk.getDetails()); + result = adaptor.connectPhysicalDisk(vol.getPath(), pool, disk.getDetails(), isVMMigrate); if (!result) { logger.error("Failed to connect disks via vm spec for vm: " + vmName + " volume:" + vol.toString()); @@ -315,6 +315,7 @@ public class KVMStoragePoolManager { URI storageUri = null; try { + logger.debug("Get storage pool by uri: " + uri); storageUri = new URI(uri); } catch (URISyntaxException e) { throw new CloudRuntimeException(e.toString()); @@ -324,7 +325,7 @@ public class KVMStoragePoolManager { String uuid = null; String sourceHost = ""; StoragePoolType protocol = null; - final String scheme = storageUri.getScheme().toLowerCase(); + final String scheme = (storageUri.getScheme() != null) ? storageUri.getScheme().toLowerCase() : ""; List acceptedSchemes = List.of("nfs", "networkfilesystem", "filesystem"); if (acceptedSchemes.contains(scheme)) { sourcePath = storageUri.getPath(); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java index 1ce901d857f..a9dfd29a4bf 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java @@ -1018,7 +1018,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { } @Override - public boolean connectPhysicalDisk(String name, KVMStoragePool pool, Map details) { + public boolean connectPhysicalDisk(String name, KVMStoragePool pool, Map details, boolean isVMMigrate) { // this is for managed storage that needs to prep disks prior to use return true; } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ManagedNfsStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ManagedNfsStorageAdaptor.java index 2304e1cbac5..3353738fd09 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ManagedNfsStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ManagedNfsStorageAdaptor.java @@ -97,7 +97,7 @@ public class ManagedNfsStorageAdaptor implements StorageAdaptor { * creates a nfs storage pool using libvirt */ @Override - public boolean connectPhysicalDisk(String volumeUuid, KVMStoragePool pool, Map details) { + public boolean connectPhysicalDisk(String volumeUuid, KVMStoragePool pool, Map details, boolean isVMMigrate) { StoragePool sp = null; Connect conn = null; diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/MultipathSCSIAdapterBase.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/MultipathSCSIAdapterBase.java index 7a827d9afc3..19d8378eb78 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/MultipathSCSIAdapterBase.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/MultipathSCSIAdapterBase.java @@ -182,7 +182,7 @@ public abstract class MultipathSCSIAdapterBase implements StorageAdaptor { } @Override - public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map details) { + public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map details, boolean isVMMigrate) { LOGGER.info("connectPhysicalDisk called for [" + volumePath + "]"); if (StringUtils.isEmpty(volumePath)) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/MultipathSCSIPool.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/MultipathSCSIPool.java index bc2f072f719..229481b1f79 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/MultipathSCSIPool.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/MultipathSCSIPool.java @@ -78,7 +78,7 @@ public class MultipathSCSIPool implements KVMStoragePool { @Override public boolean connectPhysicalDisk(String volumeUuid, Map details) { - return storageAdaptor.connectPhysicalDisk(volumeUuid, this, details); + return storageAdaptor.connectPhysicalDisk(volumeUuid, this, details, false); } @Override diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java index 7477d768e9a..335ea0d03d2 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java @@ -181,7 +181,7 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor { return null; } - if(!connectPhysicalDisk(name, pool, null)) { + if(!connectPhysicalDisk(name, pool, null, false)) { throw new CloudRuntimeException(String.format("Failed to ensure disk %s was present", name)); } @@ -224,7 +224,7 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor { } @Override - public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map details) { + public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map details, boolean isMigration) { if (StringUtils.isEmpty(volumePath) || pool == null) { logger.error("Unable to connect physical disk due to insufficient data"); throw new CloudRuntimeException("Unable to connect physical disk due to insufficient data"); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePool.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePool.java index 77f21910da6..e8243c3f7cf 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePool.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePool.java @@ -89,7 +89,7 @@ public class ScaleIOStoragePool implements KVMStoragePool { @Override public boolean connectPhysicalDisk(String volumeUuid, Map details) { - return storageAdaptor.connectPhysicalDisk(volumeUuid, this, details); + return storageAdaptor.connectPhysicalDisk(volumeUuid, this, details, false); } @Override diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java index 15b03a55a3e..8439a50073e 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java @@ -52,8 +52,15 @@ public interface StorageAdaptor { public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, byte[] passphrase); - // given disk path (per database) and pool, prepare disk on host - public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map details); + /** + * given disk path (per database) and pool, prepare disk on host + * @param volumePath volume path + * @param pool storage pool the disk is part of + * @param details disk details map + * @param isVMMigrate Indicates if request is while VM is migration + * @return true if connect was a success + */ + public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map details, boolean isVMMigrate); // given disk path (per database) and pool, clean up disk on host public boolean disconnectPhysicalDisk(String volumePath, KVMStoragePool pool); diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 15c2b46e077..961537a534e 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -1477,7 +1477,7 @@ public class LibvirtComputingResourceTest { when(libvirtComputingResourceMock.getVifDriver(nicTO.getType(), nicTO.getName())).thenReturn(vifDriver); when(libvirtComputingResourceMock.getStoragePoolMgr()).thenReturn(storagePoolManager); - when(storagePoolManager.connectPhysicalDisksViaVmSpec(vm)).thenReturn(true); + when(storagePoolManager.connectPhysicalDisksViaVmSpec(vm, true)).thenReturn(true); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); @@ -5023,7 +5023,7 @@ public class LibvirtComputingResourceTest { fail(e.getMessage()); } - when(storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec)).thenReturn(false); + when(storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec, false)).thenReturn(false); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); @@ -5224,7 +5224,7 @@ public class LibvirtComputingResourceTest { fail(e.getMessage()); } - when(storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec)).thenReturn(true); + when(storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec, false)).thenReturn(true); try { doNothing().when(libvirtComputingResourceMock).createVifs(vmSpec, vmDef); @@ -5303,7 +5303,7 @@ public class LibvirtComputingResourceTest { fail(e.getMessage()); } - when(storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec)).thenReturn(true); + when(storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec, false)).thenReturn(true); try { doNothing().when(libvirtComputingResourceMock).createVifs(vmSpec, vmDef); @@ -5380,7 +5380,7 @@ public class LibvirtComputingResourceTest { fail(e.getMessage()); } - when(storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec)).thenReturn(true); + when(storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec, false)).thenReturn(true); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java index 7989f9e6a69..ba6f9ce4b0a 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePoolTest.java @@ -190,7 +190,7 @@ public class ScaleIOStoragePoolTest { when(adapter.getPhysicalDisk(volumeId, pool)).thenReturn(disk); - final boolean result = adapter.connectPhysicalDisk(volumePath, pool, null); + final boolean result = adapter.connectPhysicalDisk(volumePath, pool, null, false); assertTrue(result); } } diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVmIpAddressCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVmIpAddressCommandWrapper.java index a324ec1bdad..dceeec17fb3 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVmIpAddressCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVmIpAddressCommandWrapper.java @@ -61,20 +61,19 @@ public final class CitrixGetVmIpAddressCommandWrapper extends CommandWrapper details) + public boolean connectPhysicalDisk( + String volumePath, KVMStoragePool pool, Map details, boolean isVMMigration) { logger.debug("Linstor: connectPhysicalDisk {}:{} -> {}", pool.getUuid(), volumePath, details); if (volumePath == null) { @@ -315,12 +318,13 @@ public class LinstorStorageAdaptor implements StorageAdaptor { throw new CloudRuntimeException(apiEx.getBestMessage(), apiEx); } - try - { - allow2PrimariesIfInUse(api, rscName); - } catch (ApiException apiEx) { - logger.error(apiEx); - // do not fail here as adding allow-two-primaries property is only a problem while live migrating + if (isVMMigration) { + try { + allow2PrimariesIfInUse(api, rscName); + } catch (ApiException apiEx) { + logger.error(apiEx); + // do not fail here as adding allow-two-primaries property is only a problem while live migrating + } } return true; } @@ -716,4 +720,19 @@ public class LinstorStorageAdaptor implements StorageAdaptor { throw new CloudRuntimeException(apiEx.getBestMessage(), apiEx); } } + + public boolean isNodeOnline(LinstorStoragePool pool, String nodeName) { + DevelopersApi linstorApi = getLinstorAPI(pool); + try { + List node = linstorApi.nodeList(Collections.singletonList(nodeName), Collections.emptyList(), null, null); + if (node == null || node.isEmpty()) { + return false; + } + + return Node.ConnectionStatusEnum.ONLINE.equals(node.get(0).getConnectionStatus()); + } catch (ApiException apiEx) { + logger.error(apiEx.getMessage()); + throw new CloudRuntimeException(apiEx.getBestMessage(), apiEx); + } + } } diff --git a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStoragePool.java b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStoragePool.java index 2d6801049a3..bb354bec9b4 100644 --- a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStoragePool.java +++ b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStoragePool.java @@ -75,7 +75,7 @@ public class LinstorStoragePool implements KVMStoragePool { @Override public boolean connectPhysicalDisk(String volumeUuid, Map details) { - return _storageAdaptor.connectPhysicalDisk(volumeUuid, this, details); + return _storageAdaptor.connectPhysicalDisk(volumeUuid, this, details, false); } @Override @@ -280,22 +280,52 @@ public class LinstorStoragePool implements KVMStoragePool { return sc.execute(parser); } + private boolean checkLinstorNodeOnline(String nodeName) { + return ((LinstorStorageAdaptor)_storageAdaptor).isNodeOnline(this, nodeName); + } + + /** + * Checks output of drbdsetup status output if this node has any valid connection to the specified + * otherNodeName. + * If there is no connection, ask the Linstor controller if the node is seen online and return false if not. + * If there is a connection but not connected(valid) return false. + * @param output Output of the drbdsetup status --json command + * @param otherNodeName Name of the node to check against + * @return true if we could say that this node thinks the node in question is reachable, otherwise false. + */ private boolean checkDrbdSetupStatusOutput(String output, String otherNodeName) { JsonParser jsonParser = new JsonParser(); JsonArray jResources = (JsonArray) jsonParser.parse(output); + boolean connectionFound = false; for (JsonElement jElem : jResources) { JsonObject jRes = (JsonObject) jElem; JsonArray jConnections = jRes.getAsJsonArray("connections"); for (JsonElement jConElem : jConnections) { JsonObject jConn = (JsonObject) jConElem; - if (jConn.getAsJsonPrimitive("name").getAsString().equals(otherNodeName) - && jConn.getAsJsonPrimitive("connection-state").getAsString().equalsIgnoreCase("Connected")) { - return true; + if (jConn.getAsJsonPrimitive("name").getAsString().equals(otherNodeName)) + { + connectionFound = true; + if (jConn.getAsJsonPrimitive("connection-state").getAsString() + .equalsIgnoreCase("Connected")) { + return true; + } } } } - LOGGER.warn(String.format("checkDrbdSetupStatusOutput: no resource connected to %s.", otherNodeName)); - return false; + boolean otherNodeOnline = false; + if (connectionFound) { + LOGGER.warn(String.format( + "checkingHeartBeat: connection found, but not in state 'Connected' to %s", otherNodeName)); + } else { + LOGGER.warn(String.format( + "checkingHeartBeat: no resource connected to %s, checking LINSTOR", otherNodeName)); + otherNodeOnline = checkLinstorNodeOnline(otherNodeName); + } + LOGGER.info(String.format( + "checkingHeartBeat: other node %s is %s.", + otherNodeName, + otherNodeOnline ? "online on controller" : "down")); + return otherNodeOnline; } private String executeDrbdEventsNow(OutputInterpreter.AllLinesParser parser) { diff --git a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java index de3886f6294..d68e9cbd110 100644 --- a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java +++ b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java @@ -249,7 +249,7 @@ public class StorPoolStorageAdaptor implements StorageAdaptor { } @Override - public boolean connectPhysicalDisk(String volumeUuid, KVMStoragePool pool, Map details) { + public boolean connectPhysicalDisk(String volumeUuid, KVMStoragePool pool, Map details, boolean isVMMigrate) { SP_LOG("StorPoolStorageAdaptor.connectPhysicalDisk: uuid=%s, pool=%s", volumeUuid, pool); LOGGER.debug(String.format("connectPhysicalDisk: uuid=%s, pool=%s", volumeUuid, pool)); diff --git a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStoragePool.java b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStoragePool.java index aa0a8849d90..ac7138420c0 100644 --- a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStoragePool.java +++ b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStoragePool.java @@ -132,7 +132,7 @@ public class StorPoolStoragePool implements KVMStoragePool { @Override public boolean connectPhysicalDisk(String name, Map details) { - return _storageAdaptor.connectPhysicalDisk(name, this, details); + return _storageAdaptor.connectPhysicalDisk(name, this, details, false); } @Override diff --git a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAMLUtils.java b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAMLUtils.java index 54f6e84fe36..364a43e93c0 100644 --- a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAMLUtils.java +++ b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAMLUtils.java @@ -321,6 +321,7 @@ public class SAMLUtils { String sessionKeyCookie = String.format("%s=%s;Domain=%s;Path=%s;%s", ApiConstants.SESSIONKEY, loginResponse.getSessionKey(), domain, path, sameSite); LOGGER.debug("Adding sessionkey cookie to response: " + sessionKeyCookie); resp.addHeader("SET-COOKIE", sessionKeyCookie); + resp.addHeader("SET-COOKIE", String.format("%s=%s;HttpOnly;Path=/client/api;%s", ApiConstants.SESSIONKEY, loginResponse.getSessionKey(), sameSite)); } /** diff --git a/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java b/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java index 3449f1f5d00..5d468d95e4c 100644 --- a/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java +++ b/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java @@ -345,10 +345,10 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle try { if (isConfigDriveIsoOnHostCache(vm.getId())) { vm.setConfigDriveLocation(Location.HOST); - configureConfigDriveData(vm, nic, dest); - - // Create the config drive on dest host cache - createConfigDriveIsoOnHostCache(nic, vm, dest.getHost().getId()); + if (configureConfigDriveData(vm, nic, dest)) { + // Create the config drive on dest host cache + createConfigDriveIsoOnHostCache(vm, dest.getHost().getId()); + } } else { vm.setConfigDriveLocation(getConfigDriveLocation(vm.getId())); boolean result = addPasswordAndUserdata(network, nic, vm, dest, context); @@ -380,7 +380,7 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle @Override public void commitMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) { try { - if (isConfigDriveIsoOnHostCache(vm.getId())) { + if (isLastConfigDriveIsoOnHostCache(vm.getId())) { vm.setConfigDriveLocation(Location.HOST); // Delete the config drive on src host cache deleteConfigDriveIsoOnHostCache(vm.getVirtualMachine(), vm.getHostId()); @@ -537,7 +537,18 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle return false; } - private boolean createConfigDriveIsoOnHostCache(NicProfile nic, VirtualMachineProfile profile, Long hostId) throws ResourceUnavailableException { + private boolean isLastConfigDriveIsoOnHostCache(long vmId) { + final UserVmDetailVO vmDetailLastConfigDriveLocation = _userVmDetailsDao.findDetail(vmId, VmDetailConstants.LAST_CONFIG_DRIVE_LOCATION); + if (vmDetailLastConfigDriveLocation == null) { + return isConfigDriveIsoOnHostCache(vmId); + } + if (Location.HOST.toString().equalsIgnoreCase(vmDetailLastConfigDriveLocation.getValue())) { + return true; + } + return false; + } + + private boolean createConfigDriveIsoOnHostCache(VirtualMachineProfile profile, Long hostId) throws ResourceUnavailableException { if (hostId == null) { throw new ResourceUnavailableException("Config drive iso creation failed, dest host not available", ConfigDriveNetworkElement.class, 0L); @@ -549,7 +560,7 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle final String isoFileName = ConfigDrive.configIsoFileName(profile.getInstanceName()); final String isoPath = ConfigDrive.createConfigDrivePath(profile.getInstanceName()); - List nicProfiles = _networkOrchestrationService.getNicProfiles(nic.getVirtualMachineId(), profile.getHypervisorType()); + List nicProfiles = _networkOrchestrationService.getNicProfiles(profile.getVirtualMachine().getId(), profile.getHypervisorType()); final Map> supportedServices = getSupportedServicesByElementForNetwork(nicProfiles); final String isoData = ConfigDriveBuilder.buildConfigDrive(nicProfiles, profile.getVmData(), isoFileName, profile.getConfigDriveLabel(), customUserdataParamMap, supportedServices); final HandleConfigDriveIsoCommand configDriveIsoCommand = new HandleConfigDriveIsoCommand(isoPath, isoData, null, false, true, true); @@ -565,7 +576,7 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle } profile.setConfigDriveLocation(answer.getConfigDriveLocation()); - _userVmDetailsDao.addDetail(profile.getId(), VmDetailConstants.CONFIG_DRIVE_LOCATION, answer.getConfigDriveLocation().toString(), false); + updateConfigDriveLocationInVMDetails(profile.getId(), answer.getConfigDriveLocation()); addConfigDriveDisk(profile, null); return true; } @@ -650,11 +661,23 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle answer.getDetails()), ConfigDriveNetworkElement.class, 0L); } profile.setConfigDriveLocation(answer.getConfigDriveLocation()); - _userVmDetailsDao.addDetail(profile.getId(), VmDetailConstants.CONFIG_DRIVE_LOCATION, answer.getConfigDriveLocation().toString(), false); + updateConfigDriveLocationInVMDetails(profile.getId(), answer.getConfigDriveLocation()); addConfigDriveDisk(profile, dataStore); return true; } + private void updateConfigDriveLocationInVMDetails(long vmId, NetworkElement.Location configDriveLocation) { + final UserVmDetailVO vmDetailConfigDriveLocation = _userVmDetailsDao.findDetail(vmId, VmDetailConstants.CONFIG_DRIVE_LOCATION); + if (vmDetailConfigDriveLocation != null) { + if (!configDriveLocation.toString().equalsIgnoreCase(vmDetailConfigDriveLocation.getValue())) { + _userVmDetailsDao.addDetail(vmId, VmDetailConstants.LAST_CONFIG_DRIVE_LOCATION, vmDetailConfigDriveLocation.getValue(), false); + } else { + _userVmDetailsDao.removeDetail(vmId, VmDetailConstants.LAST_CONFIG_DRIVE_LOCATION); + } + } + _userVmDetailsDao.addDetail(vmId, VmDetailConstants.CONFIG_DRIVE_LOCATION, configDriveLocation.toString(), false); + } + private Map getVMCustomUserdataParamMap(long vmId) { UserVmVO userVm = _userVmDao.findById(vmId); String userDataDetails = userVm.getUserDataDetails(); @@ -769,7 +792,7 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle private boolean configureConfigDriveData(final VirtualMachineProfile profile, final NicProfile nic, final DeployDestination dest) { final UserVmVO vm = _userVmDao.findById(profile.getId()); - if (vm.getType() != VirtualMachine.Type.User) { + if (vm == null || vm.getType() != VirtualMachine.Type.User) { return false; } final Nic defaultNic = _networkModel.getDefaultNic(vm.getId()); diff --git a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java index a87504cd07a..53cf838ca87 100644 --- a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java @@ -543,7 +543,7 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ // Set capabilities for vpn final Map vpnCapabilities = new HashMap(); vpnCapabilities.put(Capability.SupportedVpnProtocols, "pptp,l2tp,ipsec"); - vpnCapabilities.put(Capability.VpnTypes, "removeaccessvpn"); + vpnCapabilities.put(Capability.VpnTypes, "remoteaccessvpn"); capabilities.put(Service.Vpn, vpnCapabilities); final Map dnsCapabilities = new HashMap(); diff --git a/server/src/main/java/com/cloud/user/AccountManagerImpl.java b/server/src/main/java/com/cloud/user/AccountManagerImpl.java index bea799944be..df8069fdb6d 100644 --- a/server/src/main/java/com/cloud/user/AccountManagerImpl.java +++ b/server/src/main/java/com/cloud/user/AccountManagerImpl.java @@ -122,8 +122,6 @@ import com.cloud.network.IpAddress; import com.cloud.network.IpAddressManager; import com.cloud.network.Network; import com.cloud.network.NetworkModel; -import com.cloud.network.security.SecurityGroupService; -import com.cloud.network.security.SecurityGroupVO; import com.cloud.network.VpnUserVO; import com.cloud.network.as.AutoScaleManager; import com.cloud.network.dao.AccountGuestVlanMapDao; @@ -137,6 +135,8 @@ import com.cloud.network.dao.RemoteAccessVpnVO; import com.cloud.network.dao.VpnUserDao; import com.cloud.network.router.VirtualRouter; import com.cloud.network.security.SecurityGroupManager; +import com.cloud.network.security.SecurityGroupService; +import com.cloud.network.security.SecurityGroupVO; import com.cloud.network.security.dao.SecurityGroupDao; import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcManager; @@ -1335,16 +1335,33 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M return _userAccountDao.findById(userId); } - private boolean isValidRoleChange(Account account, Role role) { - Long currentAccRoleId = account.getRoleId(); - Role currentRole = roleService.findRole(currentAccRoleId); - - if (role.getRoleType().ordinal() < currentRole.getRoleType().ordinal() && ((account.getType() == Account.Type.NORMAL && role.getRoleType().getAccountType().ordinal() > Account.Type.NORMAL.ordinal()) || - account.getType().ordinal() > Account.Type.NORMAL.ordinal() && role.getRoleType().getAccountType().ordinal() < account.getType().ordinal() && role.getRoleType().getAccountType().ordinal() > 0)) { - throw new PermissionDeniedException(String.format("Unable to update account role to %s as you are " + - "attempting to escalate the account %s to account type %s which has higher privileges", role.getName(), account.getAccountName(), role.getRoleType().getAccountType().name())); + /* + Role change should follow the below conditions: + - Caller should not be of Unknown role type + - New role's type should not be Unknown + - Caller should not be able to escalate or de-escalate an account's role which is of higher role type + - New role should not be of type Admin with domain other than ROOT domain + */ + protected void validateRoleChange(Account account, Role role, Account caller) { + Role currentRole = roleService.findRole(account.getRoleId()); + Role callerRole = roleService.findRole(caller.getRoleId()); + String errorMsg = String.format("Unable to update account role to %s, ", role.getName()); + if (RoleType.Unknown.equals(callerRole.getRoleType())) { + throw new PermissionDeniedException(String.format("%s as the caller privileges are unknown", errorMsg)); + } + if (RoleType.Unknown.equals(role.getRoleType())) { + throw new PermissionDeniedException(String.format("%s as the new role privileges are unknown", errorMsg)); + } + if (!callerRole.getRoleType().equals(RoleType.Admin) && + (role.getRoleType().ordinal() < callerRole.getRoleType().ordinal() || + currentRole.getRoleType().ordinal() < callerRole.getRoleType().ordinal())) { + throw new PermissionDeniedException(String.format("%s as either current or new role has higher " + + "privileges than the caller", errorMsg)); + } + if (role.getRoleType().equals(RoleType.Admin) && account.getDomainId() != Domain.ROOT_DOMAIN) { + throw new PermissionDeniedException(String.format("%s as the user does not belong to the ROOT domain", + errorMsg)); } - return true; } /** @@ -2136,7 +2153,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } Role role = roleService.findRole(roleId); - isValidRoleChange(account, role); + validateRoleChange(account, role, caller); acctForUpdate.setRoleId(roleId); acctForUpdate.setType(role.getRoleType().getAccountType()); checkRoleEscalation(getCurrentCallingAccount(), acctForUpdate); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 04b64dd80a3..ce2e5585a09 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -742,8 +742,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } private class VmIpAddrFetchThread extends ManagedContextRunnable { - - long nicId; long vmId; String vmName; @@ -766,7 +764,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir boolean decrementCount = true; try { - logger.debug("Trying for vm "+ vmId +" nic Id "+nicId +" ip retrieval ..."); + logger.debug("Trying IP retrieval for VM {} ({}), nic Id {}", vmName, vmId, nicId); Answer answer = _agentMgr.send(hostId, cmd); NicVO nic = _nicDao.findById(nicId); if (answer.getResult()) { @@ -777,12 +775,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir if (nic != null) { nic.setIPv4Address(vmIp); _nicDao.update(nicId, nic); - logger.debug("Vm "+ vmId +" IP "+vmIp +" got retrieved successfully"); + logger.debug("VM {} ({}) - IP {} retrieved successfully", vmName, vmId, vmIp); vmIdCountMap.remove(nicId); decrementCount = false; ActionEventUtils.onActionEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, Domain.ROOT_DOMAIN, EventTypes.EVENT_NETWORK_EXTERNAL_DHCP_VM_IPFETCH, - "VM " + vmId + " nic id " + nicId + " ip address " + vmIp + " got fetched successfully", vmId, ApiCommandResourceType.VirtualMachine.toString()); + "VM " + vmId + ", nic id " + nicId + ", IP address " + vmIp + " fetched successfully", vmId, ApiCommandResourceType.VirtualMachine.toString()); } } } else { @@ -793,7 +791,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir _nicDao.update(nicId, nic); } if (answer.getDetails() != null) { - logger.debug("Failed to get vm ip for Vm "+ vmId + answer.getDetails()); + logger.debug("Failed to get vm ip for Vm {} ({}), details: {}", vmName, vmId, answer.getDetails()); } } } catch (OperationTimedoutException e) { @@ -804,7 +802,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir if (decrementCount) { VmAndCountDetails vmAndCount = vmIdCountMap.get(nicId); vmAndCount.decrementCount(); - logger.debug("Ip is not retrieved for VM " + vmId +" nic "+nicId + " ... decremented count to "+vmAndCount.getRetrievalCount()); + logger.debug("Ip is not retrieved for VM {} ({}) nic {} ... decremented count to {}", vmName, vmId, nicId, vmAndCount.getRetrievalCount()); vmIdCountMap.put(nicId, vmAndCount); } } diff --git a/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java b/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java index 3194af03ac4..e15476819ce 100644 --- a/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java @@ -102,6 +102,7 @@ import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; import com.cloud.utils.security.CertificateHelper; import sun.security.x509.X509CertImpl; @@ -469,10 +470,18 @@ public class DirectDownloadManagerImpl extends ManagerBase implements DirectDown @Override public Pair> uploadCertificateToHosts( String certificateCer, String alias, String hypervisor, Long zoneId, Long hostId) { - if (alias != null && (alias.equalsIgnoreCase("cloud") || alias.startsWith("cloudca"))) { + if (StringUtils.isBlank(alias)) { + throw new CloudRuntimeException("Certificate name not provided, please provide a valid name"); + } + + if (alias.equalsIgnoreCase("cloud") || alias.startsWith("cloudca")) { throw new CloudRuntimeException("Please provide a different alias name for the certificate"); } + if (!NetUtils.verifyDomainNameLabel(alias, false)) { + throw new CloudRuntimeException("The provided certificate name is invalid, please provide a valid name"); + } + List hosts; DirectDownloadCertificateVO certificateVO; HypervisorType hypervisorType = HypervisorType.getType(hypervisor); diff --git a/server/src/test/java/com/cloud/user/AccountManagerImplTest.java b/server/src/test/java/com/cloud/user/AccountManagerImplTest.java index 645c9e5aa67..3f66c6017a4 100644 --- a/server/src/test/java/com/cloud/user/AccountManagerImplTest.java +++ b/server/src/test/java/com/cloud/user/AccountManagerImplTest.java @@ -27,11 +27,14 @@ import java.util.List; import java.util.Map; import com.cloud.event.ActionEventUtils; + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleService; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; - -import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd; import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; import org.apache.cloudstack.api.response.UserTwoFactorAuthenticationSetupResponse; @@ -50,6 +53,7 @@ import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; + import org.springframework.beans.factory.NoSuchBeanDefinitionException; import com.cloud.acl.DomainChecker; @@ -120,6 +124,8 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { @Mock ConfigKey enableUserTwoFactorAuthenticationMock; + @Mock + RoleService roleService; @Before public void setUp() throws Exception { @@ -1225,4 +1231,112 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { accountManagerImpl.deleteWebhooksForAccount(1L); } } + + @Test(expected = PermissionDeniedException.class) + public void testValidateRoleChangeUnknownCaller() { + Account account = Mockito.mock(Account.class); + Mockito.when(account.getRoleId()).thenReturn(1L); + Role role = Mockito.mock(Role.class); + Mockito.when(role.getRoleType()).thenReturn(RoleType.Unknown); + Account caller = Mockito.mock(Account.class); + Mockito.when(caller.getRoleId()).thenReturn(2L); + Mockito.when(roleService.findRole(2L)).thenReturn(role); + accountManagerImpl.validateRoleChange(account, Mockito.mock(Role.class), caller); + } + + @Test(expected = PermissionDeniedException.class) + public void testValidateRoleChangeUnknownNewRole() { + Account account = Mockito.mock(Account.class); + Mockito.when(account.getRoleId()).thenReturn(1L); + Role newRole = Mockito.mock(Role.class); + Mockito.when(newRole.getRoleType()).thenReturn(RoleType.Unknown); + Role callerRole = Mockito.mock(Role.class); + Mockito.when(callerRole.getRoleType()).thenReturn(RoleType.DomainAdmin); + Account caller = Mockito.mock(Account.class); + Mockito.when(caller.getRoleId()).thenReturn(2L); + Mockito.when(roleService.findRole(2L)).thenReturn(callerRole); + accountManagerImpl.validateRoleChange(account, newRole, caller); + } + + @Test + public void testValidateRoleNewRoleSameCaller() { + Account account = Mockito.mock(Account.class); + Mockito.when(account.getRoleId()).thenReturn(1L); + Role currentRole = Mockito.mock(Role.class); + Mockito.when(currentRole.getRoleType()).thenReturn(RoleType.User); + Mockito.when(roleService.findRole(1L)).thenReturn(currentRole); + Role newRole = Mockito.mock(Role.class); + Mockito.when(newRole.getRoleType()).thenReturn(RoleType.DomainAdmin); + Role callerRole = Mockito.mock(Role.class); + Mockito.when(callerRole.getRoleType()).thenReturn(RoleType.DomainAdmin); + Account caller = Mockito.mock(Account.class); + Mockito.when(caller.getRoleId()).thenReturn(2L); + Mockito.when(roleService.findRole(2L)).thenReturn(callerRole); + accountManagerImpl.validateRoleChange(account, newRole, caller); + } + + @Test + public void testValidateRoleCurrentRoleSameCaller() { + Account account = Mockito.mock(Account.class); + Mockito.when(account.getRoleId()).thenReturn(1L); + Role accountRole = Mockito.mock(Role.class); + Mockito.when(accountRole.getRoleType()).thenReturn(RoleType.DomainAdmin); + Role newRole = Mockito.mock(Role.class); + Mockito.when(newRole.getRoleType()).thenReturn(RoleType.User); + Role callerRole = Mockito.mock(Role.class); + Mockito.when(callerRole.getRoleType()).thenReturn(RoleType.DomainAdmin); + Account caller = Mockito.mock(Account.class); + Mockito.when(caller.getRoleId()).thenReturn(2L); + Mockito.when(roleService.findRole(1L)).thenReturn(accountRole); + Mockito.when(roleService.findRole(2L)).thenReturn(callerRole); + accountManagerImpl.validateRoleChange(account, newRole, caller); + } + + @Test(expected = PermissionDeniedException.class) + public void testValidateRoleNewRoleHigherCaller() { + Account account = Mockito.mock(Account.class); + Mockito.when(account.getRoleId()).thenReturn(1L); + Role newRole = Mockito.mock(Role.class); + Mockito.when(newRole.getRoleType()).thenReturn(RoleType.Admin); + Role callerRole = Mockito.mock(Role.class); + Mockito.when(callerRole.getRoleType()).thenReturn(RoleType.DomainAdmin); + Account caller = Mockito.mock(Account.class); + Mockito.when(caller.getRoleId()).thenReturn(2L); + Mockito.when(roleService.findRole(2L)).thenReturn(callerRole); + accountManagerImpl.validateRoleChange(account, newRole, caller); + } + + @Test + public void testValidateRoleNewRoleLowerCaller() { + Account account = Mockito.mock(Account.class); + Mockito.when(account.getRoleId()).thenReturn(1L); + Role newRole = Mockito.mock(Role.class); + Mockito.when(newRole.getRoleType()).thenReturn(RoleType.User); + Role accountRole = Mockito.mock(Role.class); + Mockito.when(accountRole.getRoleType()).thenReturn(RoleType.User); + Role callerRole = Mockito.mock(Role.class); + Mockito.when(callerRole.getRoleType()).thenReturn(RoleType.DomainAdmin); + Account caller = Mockito.mock(Account.class); + Mockito.when(caller.getRoleId()).thenReturn(2L); + Mockito.when(roleService.findRole(1L)).thenReturn(accountRole); + Mockito.when(roleService.findRole(2L)).thenReturn(callerRole); + accountManagerImpl.validateRoleChange(account, newRole, caller); + } + + @Test(expected = PermissionDeniedException.class) + public void testValidateRoleAdminCannotEscalateAdminFromNonRootDomain() { + Account account = Mockito.mock(Account.class); + Mockito.when(account.getRoleId()).thenReturn(1L); + Mockito.when(account.getDomainId()).thenReturn(2L); + Role newRole = Mockito.mock(Role.class); + Mockito.when(newRole.getRoleType()).thenReturn(RoleType.Admin); + Role accountRole = Mockito.mock(Role.class); + Role callerRole = Mockito.mock(Role.class); + Mockito.when(callerRole.getRoleType()).thenReturn(RoleType.Admin); + Account caller = Mockito.mock(Account.class); + Mockito.when(caller.getRoleId()).thenReturn(2L); + Mockito.when(roleService.findRole(1L)).thenReturn(accountRole); + Mockito.when(roleService.findRole(2L)).thenReturn(callerRole); + accountManagerImpl.validateRoleChange(account, newRole, caller); + } } diff --git a/systemvm/debian/opt/cloud/bin/configure.py b/systemvm/debian/opt/cloud/bin/configure.py index 8926955e967..8d56001ccc9 100755 --- a/systemvm/debian/opt/cloud/bin/configure.py +++ b/systemvm/debian/opt/cloud/bin/configure.py @@ -1646,7 +1646,7 @@ def main(argv): ("dhcp", {"process_iptables": False, "executor": [CsDhcp("dhcpentry", config)]}), ("load_balancer", {"process_iptables": True, "executor": []}), ("monitor_service", {"process_iptables": False, "executor": [CsMonitor("monitorservice", config)]}), - ("static_routes", {"process_iptables": False, "executor": [CsStaticRoutes("staticroutes", config)]}) + ("static_routes", {"process_iptables": True, "executor": [CsStaticRoutes("staticroutes", config)]}) ]) if not config.is_vpc(): diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 49f3246461f..b6a858dd1e0 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1530,6 +1530,7 @@ "label.networkspeed": "Network speed", "label.networktype": "Network type", "label.networkwrite": "Network write", +"label.never": "Never", "label.new": "New", "label.new.autoscale.vmgroup": "New AutoScaling Group", "label.new.instance.group": "New Instance group", diff --git a/ui/src/components/menu/SMenu.vue b/ui/src/components/menu/SMenu.vue index 67603b7b924..f48b4607321 100644 --- a/ui/src/components/menu/SMenu.vue +++ b/ui/src/components/menu/SMenu.vue @@ -58,6 +58,12 @@ v-if="item.meta.icon && typeof (item.meta.icon) === 'string'" :icon="item.meta.icon" @click="() => { handleClickParentMenu(item) }" /> + {{ $t(item.meta.title) }} diff --git a/ui/src/components/view/InfoCard.vue b/ui/src/components/view/InfoCard.vue index 5b86cd9ea88..e19456ecd5c 100644 --- a/ui/src/components/view/InfoCard.vue +++ b/ui/src/components/view/InfoCard.vue @@ -34,12 +34,12 @@ - + @@ -185,7 +185,10 @@
{{ $t('label.cpu') }}
- + {{ resource.cpunumber }} CPU x {{ (resource.cpuspeed / 1000.0).toFixed(2) }} GHz