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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ public interface AgentManager {
"This timeout overrides the wait global config. This holds a comma separated key value pairs containing timeout (in seconds) for specific commands. " +
"For example: DhcpEntryCommand=600, SavePasswordCommand=300, VmDataCommand=300", false);

ConfigKey<Integer> KVMHostDiscoverySshPort = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED, Integer.class,
Copy link
Member

@winterhazel winterhazel Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to have this as a parameter on host addition/edit to allow configuring it on a host-level?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can, but do we really want to allow to use a different ssh port for all hosts within a cluster? seems a bit overkill.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a problem allowing it. Maybe a single host needs to use a different port for SSH connection.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, a bit of an edge case, only applicable to smaller installations I’d guess (in my ignorance). You are not asking to remove a higher level setting are you? just to add a per host parameter..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the config is applicable for the kvm hosts on the entire cloudstack installation, mainly for large deployments where the custom port is used for all the hosts. it doesn't provide flexibility to set few hosts on one port, and few hosts on the other. it's always better to have all these hosts accessible on the same port. a new host parameter (that can be updated through add or update host call) can provide flexibility, but it's mostly NULL/empty (when not defined or default port is used) and is not applicable for VMware hosts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nvazquez
I think it is fine to hardcode the default SSH port as 22, which is allocated by IANA
if user want to use a custom port, pass it as part of host url (host:port), it is more flexible

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guys, we have a customer asking ffor a per cluster configuration, So I propose the following;
if not part of the host field (i.e. localhost:22) check the host detail, else check the cluster setting, else 22.

makes sense everybody?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM @DaanHoogland - setting being global as it is now should also work

Copy link
Member

@winterhazel winterhazel Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DaanHoogland I suggest having either just host configuration stored on URL field -> cluster setting -> 22, or host configuration stored on host_detail -> cluster setting -> 22, depending on whichever is easier to implement without breaking compatibility.

Storing this configuration at two places for host-level seems unnecessary, and might just make it confusing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, simplifying to:
if not part of the host field (i.e. localhost:22), check the cluster setting, else 22.

"kvm.host.discovery.ssh.port", "22", "SSH port used for KVM host discovery and any other operations on host (using SSH). Please note that this is applicable for all the KVM hosts added to this CloudStack deployment, so ensure all hosts are accessible on this port", true);

enum TapAgentsAction {
Add, Del, Contains,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1977,7 +1977,7 @@ public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] { CheckTxnBeforeSending, Workers, Port, Wait, AlertWait, DirectAgentLoadSize,
DirectAgentPoolSize, DirectAgentThreadCap, EnableKVMAutoEnableDisable, ReadyCommandWait,
GranularWaitTimeForCommands, RemoteAgentSslHandshakeTimeout, RemoteAgentMaxConcurrentNewConnections,
RemoteAgentNewConnectionsMonitorInterval };
RemoteAgentNewConnectionsMonitorInterval, KVMHostDiscoverySshPort };
}

protected class SetHostParamsListener implements Listener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// under the License.
package org.apache.cloudstack.backup;

import com.cloud.agent.AgentManager;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
Expand Down Expand Up @@ -230,7 +231,7 @@ private String executeBackupCommand(HostVO host, String username, String passwor
Pattern saveTimePattern = Pattern.compile(nstRegex);

try {
Pair<Boolean, String> response = SshHelper.sshExecute(host.getPrivateIpAddress(), 22,
Pair<Boolean, String> response = SshHelper.sshExecute(host.getPrivateIpAddress(), AgentManager.KVMHostDiscoverySshPort.value(),
username, null, password, command, 120000, 120000, 3600000);
if (!response.first()) {
LOG.error(String.format("Backup Script failed on HYPERVISOR %s due to: %s", host, response.second()));
Expand All @@ -251,7 +252,7 @@ private String executeBackupCommand(HostVO host, String username, String passwor
private boolean executeRestoreCommand(HostVO host, String username, String password, String command) {

try {
Pair<Boolean, String> response = SshHelper.sshExecute(host.getPrivateIpAddress(), 22,
Pair<Boolean, String> response = SshHelper.sshExecute(host.getPrivateIpAddress(), AgentManager.KVMHostDiscoverySshPort.value(),
username, null, password, command, 120000, 120000, 3600000);

if (!response.first()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ private void setupAgentSecurity(final Connection sshConnection, final String age
}
}

sshConnection = new Connection(agentIp, 22);
sshConnection = new Connection(agentIp, AgentManager.KVMHostDiscoverySshPort.value());

sshConnection.connect(null, 60000, 60000);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2949,7 +2949,7 @@ protected Ternary<String, String, String> getHostCredentials(HostVO host) {
*/
protected void connectAndRestartAgentOnHost(HostVO host, String username, String password, String privateKey) {
final com.trilead.ssh2.Connection connection = SSHCmdHelper.acquireAuthorizedConnection(
host.getPrivateIpAddress(), 22, username, password, privateKey);
host.getPrivateIpAddress(), AgentManager.KVMHostDiscoverySshPort.value(), 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()));
}
Expand Down
2 changes: 1 addition & 1 deletion utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public static com.trilead.ssh2.Connection acquireAuthorizedConnection(String ip,
}

public static com.trilead.ssh2.Connection acquireAuthorizedConnection(String ip, int port, String username, String password) {
return acquireAuthorizedConnection(ip, 22, username, password, null);
return acquireAuthorizedConnection(ip, port, username, password, null);
}

public static boolean acquireAuthorizedConnectionWithPublicKey(final com.trilead.ssh2.Connection sshConnection, final String username, final String privateKey) {
Expand Down
Loading