diff --git a/debian/control b/debian/control index 3ab3e0491e8..066994785b3 100644 --- a/debian/control +++ b/debian/control @@ -22,7 +22,7 @@ Description: CloudStack server library Package: cloudstack-agent Architecture: all -Depends: ${python:Depends}, ${python3:Depends}, openjdk-11-jre-headless | java11-runtime-headless | java11-runtime | openjdk-11-jre-headless | zulu-11, cloudstack-common (= ${source:Version}), lsb-base (>= 9), openssh-client, qemu-kvm (>= 2.5), libvirt-bin (>= 1.3) | libvirt-daemon-system (>= 3.0), iproute2, ebtables, vlan, ipset, python3-libvirt, ethtool, iptables, lsb-release, aria2, ufw, apparmor +Depends: ${python:Depends}, ${python3:Depends}, openjdk-11-jre-headless | java11-runtime-headless | java11-runtime | openjdk-11-jre-headless | zulu-11, cloudstack-common (= ${source:Version}), lsb-base (>= 9), openssh-client, qemu-kvm (>= 2.5) | qemu-system-x86 (>= 5.2), libvirt-bin (>= 1.3) | libvirt-daemon-system (>= 3.0), iproute2, ebtables, vlan, ipset, python3-libvirt, ethtool, iptables, lsb-release, aria2, ufw, apparmor Recommends: init-system-helpers Conflicts: cloud-agent, cloud-agent-libs, cloud-agent-deps, cloud-agent-scripts Description: CloudStack agent 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 a61947d751c..f1c0ce8153c 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 @@ -3714,10 +3714,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv return null; } - if (_guestCpuArch != null && _guestCpuArch.equals("aarch64")) { - return DiskDef.DiskBus.SCSI; - } - String rootDiskController = details.get(VmDetailConstants.ROOT_DISK_CONTROLLER); if (StringUtils.isNotBlank(rootDiskController)) { s_logger.debug("Passed custom disk controller for ROOT disk " + rootDiskController); @@ -3751,10 +3747,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } private DiskDef.DiskBus getGuestDiskModel(final String platformEmulator, boolean isUefiEnabled) { - if (_guestCpuArch != null && _guestCpuArch.equals("aarch64")) { - return DiskDef.DiskBus.SCSI; - } - if (platformEmulator == null) { return DiskDef.DiskBus.IDE; } else if (platformEmulator.startsWith("Other PV Virtio-SCSI")) { @@ -3765,6 +3757,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv return DiskDef.DiskBus.VIRTIO; } else if (isUefiEnabled && StringUtils.startsWithAny(platformEmulator, "Windows", "Other")) { return DiskDef.DiskBus.SATA; + } else if (_guestCpuArch != null && _guestCpuArch.equals("aarch64")) { + return DiskDef.DiskBus.SCSI; } else { return DiskDef.DiskBus.IDE; } 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 c744299b345..4106cc05799 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 @@ -420,7 +420,7 @@ public class LibvirtComputingResourceTest { public void testCreateDevicesWithSCSIDisk() { VirtualMachineTO to = createDefaultVM(false); to.setDetails(new HashMap<>()); - libvirtComputingResourceSpy._guestCpuArch = "aarch64"; + to.setPlatformEmulator("Other PV Virtio-SCSI"); GuestDef guest = new GuestDef(); guest.setGuestType(GuestType.KVM); diff --git a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriver.java b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriver.java index 1ab9129734f..8b8c7e7e3e2 100644 --- a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriver.java +++ b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriver.java @@ -629,7 +629,7 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver { private Answer copyTemplateToVolume(DataObject srcData, DataObject destData, Host destHost) { // Copy PowerFlex/ScaleIO template to volume - LOGGER.debug("Initiating copy from PowerFlex template volume on host " + destHost != null ? destHost.getId() : ""); + LOGGER.debug(String.format("Initiating copy from PowerFlex template volume on host %s", destHost != null ? destHost.getId() : "")); int primaryStorageDownloadWait = StorageManager.PRIMARY_STORAGE_DOWNLOAD_WAIT.value(); CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); @@ -648,7 +648,7 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver { private Answer copyVolume(DataObject srcData, DataObject destData, Host destHost) { // Copy PowerFlex/ScaleIO volume - LOGGER.debug("Initiating copy from PowerFlex volume on host " + destHost != null ? destHost.getId() : ""); + LOGGER.debug(String.format("Initiating copy from PowerFlex template volume on host %s", destHost != null ? destHost.getId() : "")); String value = configDao.getValue(Config.CopyVolumeWait.key()); int copyVolumeWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index 8c44a8ce111..6f5b272dc20 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -3152,6 +3152,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q SearchCriteria cpuSearchCriteria = _srvOfferingJoinDao.createSearchCriteria(); cpuSearchCriteria.addOr("minCpu", Op.NULL); cpuSearchCriteria.addOr("constraints", Op.SC, cpuConstraintSearchCriteria); + cpuSearchCriteria.addOr("minCpu", Op.GTEQ, cpuNumber); sc.addAnd("cpuConstraints", SearchCriteria.Op.SC, cpuSearchCriteria); } @@ -3164,6 +3165,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q SearchCriteria memSearchCriteria = _srvOfferingJoinDao.createSearchCriteria(); memSearchCriteria.addOr("minMemory", Op.NULL); memSearchCriteria.addOr("memconstraints", Op.SC, memoryConstraintSearchCriteria); + memSearchCriteria.addOr("minMemory", Op.GTEQ, memory); sc.addAnd("memoryConstraints", SearchCriteria.Op.SC, memSearchCriteria); } @@ -3171,7 +3173,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q if (cpuSpeed != null) { SearchCriteria cpuSpeedSearchCriteria = _srvOfferingJoinDao.createSearchCriteria(); cpuSpeedSearchCriteria.addOr("speed", Op.NULL); - cpuSpeedSearchCriteria.addOr("speed", Op.EQ, cpuSpeed); + cpuSpeedSearchCriteria.addOr("speed", Op.GTEQ, cpuSpeed); sc.addAnd("cpuspeedconstraints", SearchCriteria.Op.SC, cpuSpeedSearchCriteria); } diff --git a/server/src/main/java/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java b/server/src/main/java/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java index e63a992ec4b..818c14f5b25 100644 --- a/server/src/main/java/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java +++ b/server/src/main/java/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java @@ -259,9 +259,17 @@ public abstract class LibvirtServerDiscoverer extends DiscovererBase implements sshConnection = new Connection(agentIp, 22); sshConnection.connect(null, 60000, 60000); - if (!sshConnection.authenticateWithPassword(username, password)) { - s_logger.debug("Failed to authenticate"); - throw new DiscoveredWithErrorException("Authentication error"); + + final String privateKey = _configDao.getValue("ssh.privatekey"); + if (!SSHCmdHelper.acquireAuthorizedConnectionWithPublicKey(sshConnection, username, privateKey)) { + s_logger.error("Failed to authenticate with ssh key"); + if (org.apache.commons.lang3.StringUtils.isEmpty(password)) { + throw new DiscoveredWithErrorException("Authentication error with ssh private key"); + } + if (!sshConnection.authenticateWithPassword(username, password)) { + s_logger.error("Failed to authenticate with password"); + throw new DiscoveredWithErrorException("Authentication error with host password"); + } } if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "ls /dev/kvm")) { diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index 60a7648b414..fa970be7e4a 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -165,7 +165,8 @@ import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; -import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; +import com.cloud.utils.StringUtils; import com.cloud.utils.UriUtils; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; @@ -695,9 +696,16 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, throw new InvalidParameterValueException("Can't specify cluster without specifying the pod"); } List skipList = Arrays.asList(HypervisorType.VMware.name().toLowerCase(Locale.ROOT), Type.SecondaryStorage.name().toLowerCase(Locale.ROOT)); - if (!skipList.contains(hypervisorType.toLowerCase(Locale.ROOT)) && - (StringUtils.isAnyEmpty(username, password))) { - throw new InvalidParameterValueException("Username and Password need to be provided."); + if (!skipList.contains(hypervisorType.toLowerCase(Locale.ROOT))) { + if (HypervisorType.KVM.toString().equalsIgnoreCase(hypervisorType)) { + if (org.apache.commons.lang3.StringUtils.isBlank(username)) { + throw new InvalidParameterValueException("Username need to be provided."); + } + } else { + if (org.apache.commons.lang3.StringUtils.isBlank(username) || org.apache.commons.lang3.StringUtils.isBlank(password)) { + throw new InvalidParameterValueException("Username and Password need to be provided."); + } + } } if (clusterId != null) { @@ -2731,8 +2739,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } final boolean sshToAgent = Boolean.parseBoolean(_configDao.getValue(KvmSshToAgentEnabled.key())); if (sshToAgent) { - Pair credentials = getHostCredentials(host); - connectAndRestartAgentOnHost(host, credentials.first(), credentials.second()); + Ternary credentials = getHostCredentials(host); + connectAndRestartAgentOnHost(host, credentials.first(), credentials.second(), credentials.third()); } else { throw new CloudRuntimeException("SSH access is disabled, cannot cancel maintenance mode as " + "host agent is not connected"); @@ -2743,22 +2751,23 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, * Get host credentials * @throws CloudRuntimeException if username or password are not found */ - protected Pair getHostCredentials(HostVO host) { + protected Ternary getHostCredentials(HostVO host) { _hostDao.loadDetails(host); final String password = host.getDetail("password"); final String username = host.getDetail("username"); - if (password == null || username == null) { - throw new CloudRuntimeException("SSH to agent is enabled, but username/password credentials are not found"); + final String privateKey = _configDao.getValue("ssh.privatekey"); + if ((password == null && privateKey == null) || username == null) { + throw new CloudRuntimeException("SSH to agent is enabled, but username and password or private key are not found"); } - return new Pair<>(username, password); + return new Ternary<>(username, password, privateKey); } /** * True if agent is restarted via SSH. Assumes kvm.ssh.to.agent = true and host status is not Up */ - protected void connectAndRestartAgentOnHost(HostVO host, String username, String password) { + protected void connectAndRestartAgentOnHost(HostVO host, String username, String password, String privateKey) { final com.trilead.ssh2.Connection connection = SSHCmdHelper.acquireAuthorizedConnection( - host.getPrivateIpAddress(), 22, username, password); + host.getPrivateIpAddress(), 22, username, password, privateKey); if (connection == null) { throw new CloudRuntimeException(String.format("SSH to agent is enabled, but failed to connect to %s via IP address [%s].", host, host.getPrivateIpAddress())); } diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java index 4b6a55d8176..84d058dbc2b 100644 --- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java @@ -2136,6 +2136,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C if (hostIds.isEmpty()) { return null; } + Collections.shuffle(hostIds); for (Long hostId : hostIds) { Host host = _hostDao.findById(hostId); diff --git a/server/src/test/java/com/cloud/resource/ResourceManagerImplTest.java b/server/src/test/java/com/cloud/resource/ResourceManagerImplTest.java index abc03ad3d70..79d50d84ebc 100644 --- a/server/src/test/java/com/cloud/resource/ResourceManagerImplTest.java +++ b/server/src/test/java/com/cloud/resource/ResourceManagerImplTest.java @@ -67,7 +67,7 @@ import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; import com.cloud.storage.StorageManager; -import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.ssh.SSHCmdHelper; @@ -125,6 +125,7 @@ public class ResourceManagerImplTest { private static long hostId = 1L; private static final String hostUsername = "user"; private static final String hostPassword = "password"; + private static final String hostPrivateKey = "privatekey"; private static final String hostPrivateIp = "192.168.1.10"; private static long vm1Id = 1L; @@ -148,6 +149,7 @@ public class ResourceManagerImplTest { when(hostDao.findById(hostId)).thenReturn(host); when(host.getDetail("username")).thenReturn(hostUsername); when(host.getDetail("password")).thenReturn(hostPassword); + when(configurationDao.getValue("ssh.privatekey")).thenReturn(hostPrivateKey); when(host.getStatus()).thenReturn(Status.Up); when(host.getPrivateIpAddress()).thenReturn(hostPrivateIp); when(vm1.getId()).thenReturn(vm1Id); @@ -171,7 +173,7 @@ public class ResourceManagerImplTest { PowerMockito.mockStatic(SSHCmdHelper.class); BDDMockito.given(SSHCmdHelper.acquireAuthorizedConnection(eq(hostPrivateIp), eq(22), - eq(hostUsername), eq(hostPassword))).willReturn(sshConnection); + eq(hostUsername), eq(hostPassword), eq(hostPrivateKey))).willReturn(sshConnection); BDDMockito.given(SSHCmdHelper.sshExecuteCmdOneShot(eq(sshConnection), eq("service cloudstack-agent restart"))). willReturn(new SSHCmdHelper.SSHCmdResult(0,"","")); @@ -292,34 +294,36 @@ public class ResourceManagerImplTest { @Test(expected = CloudRuntimeException.class) public void testGetHostCredentialsMissingParameter() { when(host.getDetail("password")).thenReturn(null); + when(configurationDao.getValue("ssh.privatekey")).thenReturn(null); resourceManager.getHostCredentials(host); } @Test public void testGetHostCredentials() { - Pair credentials = resourceManager.getHostCredentials(host); + Ternary credentials = resourceManager.getHostCredentials(host); Assert.assertNotNull(credentials); Assert.assertEquals(hostUsername, credentials.first()); Assert.assertEquals(hostPassword, credentials.second()); + Assert.assertEquals(hostPrivateKey, credentials.third()); } @Test(expected = CloudRuntimeException.class) public void testConnectAndRestartAgentOnHostCannotConnect() { BDDMockito.given(SSHCmdHelper.acquireAuthorizedConnection(eq(hostPrivateIp), eq(22), - eq(hostUsername), eq(hostPassword))).willReturn(null); - resourceManager.connectAndRestartAgentOnHost(host, hostUsername, hostPassword); + eq(hostUsername), eq(hostPassword), eq(hostPrivateKey))).willReturn(null); + resourceManager.connectAndRestartAgentOnHost(host, hostUsername, hostPassword, hostPrivateKey); } @Test(expected = CloudRuntimeException.class) public void testConnectAndRestartAgentOnHostCannotRestart() throws Exception { BDDMockito.given(SSHCmdHelper.sshExecuteCmdOneShot(eq(sshConnection), eq("service cloudstack-agent restart"))).willThrow(new SshException("exception")); - resourceManager.connectAndRestartAgentOnHost(host, hostUsername, hostPassword); + resourceManager.connectAndRestartAgentOnHost(host, hostUsername, hostPassword, hostPrivateKey); } @Test public void testConnectAndRestartAgentOnHost() { - resourceManager.connectAndRestartAgentOnHost(host, hostUsername, hostPassword); + resourceManager.connectAndRestartAgentOnHost(host, hostUsername, hostPassword, hostPrivateKey); } @Test @@ -327,7 +331,7 @@ public class ResourceManagerImplTest { when(host.getStatus()).thenReturn(Status.Disconnected); resourceManager.handleAgentIfNotConnected(host, false); verify(resourceManager).getHostCredentials(eq(host)); - verify(resourceManager).connectAndRestartAgentOnHost(eq(host), eq(hostUsername), eq(hostPassword)); + verify(resourceManager).connectAndRestartAgentOnHost(eq(host), eq(hostUsername), eq(hostPassword), eq(hostPrivateKey)); } @Test @@ -335,7 +339,7 @@ public class ResourceManagerImplTest { when(host.getStatus()).thenReturn(Status.Up); resourceManager.handleAgentIfNotConnected(host, false); verify(resourceManager, never()).getHostCredentials(eq(host)); - verify(resourceManager, never()).connectAndRestartAgentOnHost(eq(host), eq(hostUsername), eq(hostPassword)); + verify(resourceManager, never()).connectAndRestartAgentOnHost(eq(host), eq(hostUsername), eq(hostPassword), eq(hostPrivateKey)); } @Test(expected = CloudRuntimeException.class) @@ -351,14 +355,14 @@ public class ResourceManagerImplTest { when(configurationDao.getValue(ResourceManager.KvmSshToAgentEnabled.key())).thenReturn("false"); resourceManager.handleAgentIfNotConnected(host, false); verify(resourceManager, never()).getHostCredentials(eq(host)); - verify(resourceManager, never()).connectAndRestartAgentOnHost(eq(host), eq(hostUsername), eq(hostPassword)); + verify(resourceManager, never()).connectAndRestartAgentOnHost(eq(host), eq(hostUsername), eq(hostPassword), eq(hostPrivateKey)); } @Test public void testHandleAgentVMsMigrating() { resourceManager.handleAgentIfNotConnected(host, true); verify(resourceManager, never()).getHostCredentials(eq(host)); - verify(resourceManager, never()).connectAndRestartAgentOnHost(eq(host), eq(hostUsername), eq(hostPassword)); + verify(resourceManager, never()).connectAndRestartAgentOnHost(eq(host), eq(hostUsername), eq(hostPassword), eq(hostPrivateKey)); } private void setupNoPendingMigrationRetries() { diff --git a/test/integration/component/test_configdrive.py b/test/integration/component/test_configdrive.py index 46494f0bd65..3df175f672f 100644 --- a/test/integration/component/test_configdrive.py +++ b/test/integration/component/test_configdrive.py @@ -635,7 +635,7 @@ class ConfigDriveUtils: """ ssh.execute("umount -d %s" % mount_path) # Give the VM time to unlock the iso device - time.sleep(2) + time.sleep(0.5) # Verify umount result = ssh.execute("ls %s" % mount_path) self.assertTrue(len(result) == 0, @@ -1089,10 +1089,8 @@ class ConfigDriveUtils: vm.details = vm_new_ssh.details - # reset SSH key also resets the password. - self._decrypt_password(vm) - - vm.password_test = ConfigDriveUtils.PasswordTest(vm=vm) + # reset SSH key also removes the password (see https://github.com/apache/cloudstack/pull/4819) + vm.password_test = ConfigDriveUtils.PasswordTest(expect_pw=False) vm.key_pair = self.keypair if public_ip: @@ -1119,7 +1117,7 @@ class ConfigDriveUtils: cipher = PKCS1_v1_5.new(key) new_password = cipher.decrypt(b64decode(password_), None) if new_password: - vm.password = new_password + vm.password = new_password.decode() else: self.fail("Failed to decrypt new password") except ImportError: @@ -1511,7 +1509,6 @@ class TestConfigDrive(cloudstackTestCase, ConfigDriveUtils): tries = 1 if negative_test else 3 private_key_file_location = keypair.private_key_file if keypair else None - @retry(tries=tries) def retry_ssh(): ssh_client = vm.get_ssh_client( ipaddress=public_ip.ipaddress.ipaddress, @@ -1732,8 +1729,7 @@ class TestConfigDrive(cloudstackTestCase, ConfigDriveUtils): self.api_client.restartVPC(cmd) self.debug("Restarted VPC with ID - %s" % vpc.id) - # was tags=["advanced", "isonw"] - @attr(tags=["TODO"], required_hardware="true") + @attr(tags=["advanced", "isonw"], required_hardware="true") def test_configdrive_isolated_network(self): """Test Configdrive as provider for isolated Networks to provide userdata and password reset functionality @@ -2500,6 +2496,7 @@ class TestConfigDrive(cloudstackTestCase, ConfigDriveUtils): # ===================================================================== self.debug("+++ Scenario: " "validate updated userdata after migrate") + time.sleep(30) host = self.migrate_VM(vm) vm.hostname = host.name self.then_config_drive_is_as_expected(vm, public_ip_1, metadata=True) diff --git a/ui/public/config.json b/ui/public/config.json index 6c134087101..e9994804568 100644 --- a/ui/public/config.json +++ b/ui/public/config.json @@ -10,6 +10,7 @@ "docBase": "http://docs.cloudstack.apache.org/en/latest", "appTitle": "CloudStack", "footer": "Licensed under the Apache License, Version 2.0.", + "loginFooter": "", "logo": "assets/logo.svg", "banner": "assets/banner.svg", "error": { diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 4111e0a7414..2901126a17d 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -468,6 +468,8 @@ "label.associatednetworkid": "Associated Network ID", "label.associatednetworkname": "Network Name", "label.asyncbackup": "Async Backup", +"label.authentication.method": "Authentication Method", +"label.authentication.sshkey": "System SSH Key", "label.author.email": "Author e-mail", "label.author.name": "Author name", "label.auto.assign": "Automatically assign", @@ -577,6 +579,7 @@ "label.cks.cluster.size": "Cluster size (Worker nodes)", "label.cleanup": "Clean up", "label.clear": "Clear", +"label.clear.notification": "Clear notification", "label.clear.list": "Clear list", "label.close": "Close", "label.cloud.console": "Cloud Management Console", @@ -2595,6 +2598,7 @@ "message.add.firewall.rule.processing": "Adding new Firewall rule...", "message.add.guest.network": "Please confirm that you would like to add a guest network", "message.add.host": "Please specify the following parameters to add a new host", +"message.add.host.sshkey": "WARNING: In order to add a host with SSH key, you must ensure your hypervisor host has been configured correctly.", "message.add.ip.range": "Add an IP range to public network in zone", "message.add.ip.range.direct.network": "Add an IP range to direct network in zone ", "message.add.ip.range.to.pod": "

Add an IP range to pod:

", diff --git a/ui/src/components/CheckBoxSelectPair.vue b/ui/src/components/CheckBoxSelectPair.vue index 29035e6b7d7..c0fcd9aaeda 100644 --- a/ui/src/components/CheckBoxSelectPair.vue +++ b/ui/src/components/CheckBoxSelectPair.vue @@ -20,7 +20,6 @@ {{ checkBoxLabel }} @@ -31,8 +30,7 @@ v-if="reversed != checked" :label="selectLabel"> {{ $t('label.clear.notification') }} + @@ -128,7 +135,8 @@ export default { return { collapsed: false, menus: [], - showSetting: false + showSetting: false, + showClear: false } }, computed: { @@ -161,6 +169,12 @@ export default { } else { document.body.classList.remove('dark-mode') } + }, + '$store.getters.countNotify' (countNotify) { + this.showClear = false + if (countNotify && countNotify > 0) { + this.showClear = true + } } }, provide: function () { @@ -212,6 +226,10 @@ export default { }, toggleSetting (showSetting) { this.showSetting = showSetting + }, + onClearNotification () { + this.$notification.destroy() + this.$store.commit('SET_COUNT_NOTIFY', 0) } } } diff --git a/ui/src/components/view/DetailSettings.vue b/ui/src/components/view/DetailSettings.vue index 2588c11fb2e..07f0a49cefd 100644 --- a/ui/src/components/view/DetailSettings.vue +++ b/ui/src/components/view/DetailSettings.vue @@ -219,7 +219,8 @@ export default { apiName = 'updateTemplate' } if (!(apiName in this.$store.getters.apis)) { - this.$notification.error({ + this.$showNotification({ + type: 'error', message: this.$t('error.execute.api.failed') + ' ' + apiName, description: this.$t('message.user.not.permitted.api') }) diff --git a/ui/src/components/view/InfoCard.vue b/ui/src/components/view/InfoCard.vue index fadead44684..6347c4c3a89 100644 --- a/ui/src/components/view/InfoCard.vue +++ b/ui/src/components/view/InfoCard.vue @@ -651,7 +651,7 @@ -