diff --git a/api/src/main/java/com/cloud/host/Host.java b/api/src/main/java/com/cloud/host/Host.java index 07a0dfce041..9c011bac319 100644 --- a/api/src/main/java/com/cloud/host/Host.java +++ b/api/src/main/java/com/cloud/host/Host.java @@ -59,6 +59,9 @@ public interface Host extends StateObject, Identity, Partition, HAResour String HOST_INSTANCE_CONVERSION = "host.instance.conversion"; String HOST_OVFTOOL_VERSION = "host.ovftool.version"; String HOST_VIRTV2V_VERSION = "host.virtv2v.version"; + String HOST_SSH_PORT = "host.ssh.port"; + + int DEFAULT_SSH_PORT = 22; /** * @return name of the machine. diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/AddHostCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/AddHostCmd.java index a698a62254e..5a175834560 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/AddHostCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/AddHostCmd.java @@ -60,7 +60,8 @@ public class AddHostCmd extends BaseCmd { @Parameter(name = ApiConstants.POD_ID, type = CommandType.UUID, entityType = PodResponse.class, required = true, description = "The Pod ID for the host") private Long podId; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, description = "The host URL") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, description = "The host URL, optionally add ssh port (format: 'host:port') for KVM hosts," + + " otherwise falls back to the port defined at the config 'kvm.host.discovery.ssh.port'") private String url; @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "The Zone ID for the host") diff --git a/engine/components-api/src/main/java/com/cloud/agent/AgentManager.java b/engine/components-api/src/main/java/com/cloud/agent/AgentManager.java index 0aa5805b160..4d63fae3356 100644 --- a/engine/components-api/src/main/java/com/cloud/agent/AgentManager.java +++ b/engine/components-api/src/main/java/com/cloud/agent/AgentManager.java @@ -54,6 +54,10 @@ 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 KVMHostDiscoverySshPort = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED, Integer.class, + "kvm.host.discovery.ssh.port", String.valueOf(Host.DEFAULT_SSH_PORT), "SSH port used for KVM host discovery and any other operations on host (using SSH)." + + " Please note that this is applicable when port is not defined through host url while adding the KVM host.", true, ConfigKey.Scope.Cluster); + enum TapAgentsAction { Add, Del, Contains, } @@ -172,4 +176,6 @@ public interface AgentManager { void propagateChangeToAgents(Map params); boolean transferDirectAgentsFromMS(String fromMsUuid, long fromMsId, long timeoutDurationInMs, boolean excludeHostsInMaintenance); + + int getHostSshPort(HostVO host); } diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java index 439bdf92ddd..527c5259376 100644 --- a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java @@ -42,6 +42,7 @@ import java.util.stream.Collectors; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.utils.StringUtils; import org.apache.cloudstack.agent.lb.IndirectAgentLB; import org.apache.cloudstack.ca.CAManager; import org.apache.cloudstack.command.ReconcileCommandService; @@ -64,7 +65,6 @@ import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToSt import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.ThreadContext; import com.cloud.agent.AgentManager; @@ -2111,7 +2111,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl return new ConfigKey[] { CheckTxnBeforeSending, Workers, Port, Wait, AlertWait, DirectAgentLoadSize, DirectAgentPoolSize, DirectAgentThreadCap, EnableKVMAutoEnableDisable, ReadyCommandWait, GranularWaitTimeForCommands, RemoteAgentSslHandshakeTimeout, RemoteAgentMaxConcurrentNewConnections, - RemoteAgentNewConnectionsMonitorInterval }; + RemoteAgentNewConnectionsMonitorInterval, KVMHostDiscoverySshPort }; } protected class SetHostParamsListener implements Listener { @@ -2234,6 +2234,25 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl return true; } + @Override + public int getHostSshPort(HostVO host) { + if (host == null) { + return KVMHostDiscoverySshPort.value(); + } + + if (host.getHypervisorType() != HypervisorType.KVM) { + return Host.DEFAULT_SSH_PORT; + } + + _hostDao.loadDetails(host); + String hostPort = host.getDetail(Host.HOST_SSH_PORT); + if (StringUtils.isBlank(hostPort)) { + return KVMHostDiscoverySshPort.valueIn(host.getClusterId()); + } + + return Integer.parseInt(hostPort); + } + private GlobalLock getHostJoinLock(Long hostId) { return GlobalLock.getInternLock(String.format("%s-%s", "Host-Join", hostId)); } diff --git a/engine/orchestration/src/test/java/com/cloud/agent/manager/AgentManagerImplTest.java b/engine/orchestration/src/test/java/com/cloud/agent/manager/AgentManagerImplTest.java index fb42f247788..43d83a672c0 100644 --- a/engine/orchestration/src/test/java/com/cloud/agent/manager/AgentManagerImplTest.java +++ b/engine/orchestration/src/test/java/com/cloud/agent/manager/AgentManagerImplTest.java @@ -22,6 +22,7 @@ import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.exception.ConnectionException; +import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; @@ -104,4 +105,36 @@ public class AgentManagerImplTest { Assert.assertEquals(50, result); } + + @Test + public void testGetHostSshPortWithHostNull() { + int hostSshPort = mgr.getHostSshPort(null); + Assert.assertEquals(22, hostSshPort); + } + + @Test + public void testGetHostSshPortWithNonKVMHost() { + HostVO host = Mockito.mock(HostVO.class); + Mockito.when(host.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.XenServer); + int hostSshPort = mgr.getHostSshPort(host); + Assert.assertEquals(22, hostSshPort); + } + + @Test + public void testGetHostSshPortWithKVMHostDefaultPort() { + HostVO host = Mockito.mock(HostVO.class); + Mockito.when(host.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); + Mockito.when(host.getClusterId()).thenReturn(1L); + int hostSshPort = mgr.getHostSshPort(host); + Assert.assertEquals(22, hostSshPort); + } + + @Test + public void testGetHostSshPortWithKVMHostCustomPort() { + HostVO host = Mockito.mock(HostVO.class); + Mockito.when(host.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); + Mockito.when(host.getDetail(Host.HOST_SSH_PORT)).thenReturn(String.valueOf(3922)); + int hostSshPort = mgr.getHostSshPort(host); + Assert.assertEquals(3922, hostSshPort); + } } diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java index 286d4ff7542..727c4fe8ef2 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java @@ -383,7 +383,7 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol public VolumeDaoImpl() { AllFieldsSearch = createSearchBuilder(); - AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ); + AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.IN); AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), Op.EQ); AllFieldsSearch.and("dcId", AllFieldsSearch.entity().getDataCenterId(), Op.EQ); AllFieldsSearch.and("pod", AllFieldsSearch.entity().getPodId(), Op.EQ); @@ -581,17 +581,16 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol @Override public List listVolumesToBeDestroyed() { - SearchCriteria sc = AllFieldsSearch.create(); - sc.setParameters("state", Volume.State.Destroy); - - return listBy(sc); + return listVolumesToBeDestroyed(null); } @Override public List listVolumesToBeDestroyed(Date date) { SearchCriteria sc = AllFieldsSearch.create(); - sc.setParameters("state", Volume.State.Destroy); - sc.setParameters("updateTime", date); + sc.setParameters("state", Volume.State.Destroy, Volume.State.Expunging); + if (date != null) { + sc.setParameters("updateTime", date); + } return listBy(sc); } diff --git a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 7132d61ed3b..436f991afbd 100644 --- a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -436,6 +436,9 @@ public class VolumeServiceImpl implements VolumeService { // no need to change state in volumes table volume.processEventOnly(Event.DestroyRequested); } else if (volume.getDataStore().getRole() == DataStoreRole.Primary) { + if (vol.getState() == Volume.State.Expunging) { + logger.info("Volume {} is already in Expunging, retrying", volume); + } volume.processEvent(Event.ExpungeRequested); } diff --git a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java index 66b633e11a9..4cf4bd111ef 100644 --- a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java +++ b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java @@ -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; @@ -134,6 +135,9 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid @Inject private DiskOfferingDao diskOfferingDao; + @Inject + private AgentManager agentMgr; + private static String getUrlDomain(String url) throws URISyntaxException { URI uri; try { @@ -251,8 +255,13 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid String nstRegex = "\\bcompleted savetime=([0-9]{10})"; Pattern saveTimePattern = Pattern.compile(nstRegex); + if (host == null) { + LOG.warn("Unable to take backup, host is null"); + return null; + } + try { - Pair response = SshHelper.sshExecute(host.getPrivateIpAddress(), 22, + Pair response = SshHelper.sshExecute(host.getPrivateIpAddress(), agentMgr.getHostSshPort(host), username, null, password, command, 120000, 120000, 3600000); if (!response.first()) { LOG.error("Backup Script failed on HYPERVISOR {} due to: {}", host, response.second()); @@ -271,9 +280,13 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid return null; } private boolean executeRestoreCommand(HostVO host, String username, String password, String command) { + if (host == null) { + LOG.warn("Unable to restore backup, host is null"); + return false; + } try { - Pair response = SshHelper.sshExecute(host.getPrivateIpAddress(), 22, + Pair response = SshHelper.sshExecute(host.getPrivateIpAddress(), agentMgr.getHostSshPort(host), username, null, password, command, 120000, 120000, 3600000); if (!response.first()) { diff --git a/plugins/event-bus/rabbitmq/src/main/java/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java b/plugins/event-bus/rabbitmq/src/main/java/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java index 224e49f91a3..b98147b5f03 100644 --- a/plugins/event-bus/rabbitmq/src/main/java/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java +++ b/plugins/event-bus/rabbitmq/src/main/java/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java @@ -493,7 +493,7 @@ public class RabbitMQEventBus extends ManagerBase implements EventBus { @Override public synchronized boolean stop() { - if (s_connection.isOpen()) { + if (s_connection != null && s_connection.isOpen()) { for (String subscriberId : s_subscribers.keySet()) { Ternary subscriberDetails = s_subscribers.get(subscriberId); Channel channel = subscriberDetails.second(); diff --git a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java index ced34068bb8..57f71c4ea80 100644 --- a/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java +++ b/plugins/user-authenticators/oauth2/src/main/java/org/apache/cloudstack/oauth2/api/command/OauthLoginAPIAuthenticatorCmd.java @@ -184,12 +184,8 @@ public class OauthLoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent protected Long getDomainIdFromParams(Map params, StringBuilder auditTrailSb, String responseType) { String[] domainIdArr = (String[])params.get(ApiConstants.DOMAIN_ID); - - if (domainIdArr == null) { - domainIdArr = (String[])params.get(ApiConstants.DOMAIN__ID); - } Long domainId = null; - if ((domainIdArr != null) && (domainIdArr.length > 0)) { + if (domainIdArr != null && domainIdArr.length > 0) { try { //check if UUID is passed in for domain domainId = _apiServer.fetchDomainId(domainIdArr[0]); diff --git a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java index bfd47922142..584f2463754 100644 --- a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java +++ b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java @@ -158,11 +158,17 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent String domainPath = null; if (params.containsKey(ApiConstants.IDP_ID)) { - idpId = ((String[])params.get(ApiConstants.IDP_ID))[0]; + String[] idpIds = (String[])params.get(ApiConstants.IDP_ID); + if (idpIds != null && idpIds.length > 0) { + idpId = idpIds[0]; + } } if (params.containsKey(ApiConstants.DOMAIN)) { - domainPath = ((String[])params.get(ApiConstants.DOMAIN))[0]; + String[] domainPaths = (String[])params.get(ApiConstants.DOMAIN); + if (domainPaths != null && domainPaths.length > 0) { + domainPath = domainPaths[0]; + } } if (domainPath != null && !domainPath.isEmpty()) { diff --git a/server/src/main/java/com/cloud/api/ApiServlet.java b/server/src/main/java/com/cloud/api/ApiServlet.java index 158df224071..dd99b4e13ca 100644 --- a/server/src/main/java/com/cloud/api/ApiServlet.java +++ b/server/src/main/java/com/cloud/api/ApiServlet.java @@ -38,6 +38,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.cloudstack.api.APICommand; +import com.cloud.api.auth.DefaultForgotPasswordAPIAuthenticatorCmd; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ApiServerService; @@ -200,7 +201,6 @@ public class ApiServlet extends HttpServlet { LOGGER.warn(message); } }); - } void processRequestInContext(final HttpServletRequest req, final HttpServletResponse resp) { @@ -273,7 +273,6 @@ public class ApiServlet extends HttpServlet { } if (command != null && !command.equals(ValidateUserTwoFactorAuthenticationCodeCmd.APINAME)) { - APIAuthenticator apiAuthenticator = authManager.getAPIAuthenticator(command); if (apiAuthenticator != null) { auditTrailSb.append("command="); @@ -309,7 +308,9 @@ public class ApiServlet extends HttpServlet { } catch (ServerApiException e) { httpResponseCode = e.getErrorCode().getHttpCode(); responseString = e.getMessage(); - LOGGER.debug("Authentication failure: " + e.getMessage()); + if (!DefaultForgotPasswordAPIAuthenticatorCmd.APINAME.equalsIgnoreCase(command) || StringUtils.isNotBlank(username)) { + LOGGER.debug("Authentication failure: {}", e.getMessage()); + } } if (apiAuthenticator.getAPIType() == APIAuthenticationType.LOGOUT_API) { @@ -390,7 +391,7 @@ public class ApiServlet extends HttpServlet { } } - if (! requestChecksoutAsSane(resp, auditTrailSb, responseType, params, session, command, userId, account, accountObj)) + if (!requestChecksoutAsSane(resp, auditTrailSb, responseType, params, session, command, userId, account, accountObj)) return; } else { CallContext.register(accountMgr.getSystemUser(), accountMgr.getSystemAccount()); @@ -422,7 +423,6 @@ public class ApiServlet extends HttpServlet { apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params, responseType); HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.JSONcontentType.value()); - } } catch (final ServerApiException se) { final String serializedResponseText = apiServer.getSerializedApiError(se, params, responseType); @@ -653,6 +653,9 @@ public class ApiServlet extends HttpServlet { if (LOGGER.isTraceEnabled()) { LOGGER.trace(msg); } + if (session == null) { + return; + } session.invalidate(); } catch (final IllegalStateException ise) { if (LOGGER.isTraceEnabled()) { diff --git a/server/src/main/java/com/cloud/api/auth/DefaultForgotPasswordAPIAuthenticatorCmd.java b/server/src/main/java/com/cloud/api/auth/DefaultForgotPasswordAPIAuthenticatorCmd.java index 1e90b43c5e8..46a9dd9bfe3 100644 --- a/server/src/main/java/com/cloud/api/auth/DefaultForgotPasswordAPIAuthenticatorCmd.java +++ b/server/src/main/java/com/cloud/api/auth/DefaultForgotPasswordAPIAuthenticatorCmd.java @@ -44,13 +44,13 @@ import java.net.InetAddress; import java.util.List; import java.util.Map; -@APICommand(name = "forgotPassword", +@APICommand(name = DefaultForgotPasswordAPIAuthenticatorCmd.APINAME, description = "Sends an email to the user with a token to reset the password using resetPassword command.", since = "4.20.0.0", requestHasSensitiveInfo = true, responseObject = SuccessResponse.class) public class DefaultForgotPasswordAPIAuthenticatorCmd extends BaseCmd implements APIAuthenticator { - + public static final String APINAME = "forgotPassword"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// @@ -108,10 +108,12 @@ public class DefaultForgotPasswordAPIAuthenticatorCmd extends BaseCmd implements if (userDomain != null) { domainId = userDomain.getId(); } else { + logger.debug("Unable to find the domain from the path {}", domain); throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Unable to find the domain from the path %s", domain)); } final UserAccount userAccount = _accountService.getActiveUserAccount(username[0], domainId); if (userAccount != null && List.of(User.Source.SAML2, User.Source.OAUTH2, User.Source.LDAP).contains(userAccount.getSource())) { + logger.debug("Forgot Password is not allowed for the user {} from source {}", username[0], userAccount.getSource()); throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Forgot Password is not allowed for this user"); } boolean success = _apiServer.forgotPassword(userAccount, userDomain); diff --git a/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java b/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java index dc220b1b836..4514ed83178 100644 --- a/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java +++ b/server/src/main/java/com/cloud/api/auth/DefaultLoginAPIAuthenticatorCmd.java @@ -49,7 +49,6 @@ import java.net.InetAddress; @APICommand(name = "login", description = "Logs a user into the CloudStack. A successful login attempt will generate a JSESSIONID cookie value that can be passed in subsequent Query command calls until the \"logout\" command has been issued or the session has expired.", requestHasSensitiveInfo = true, responseObject = LoginCmdResponse.class, entityType = {}) public class DefaultLoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthenticator { - ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @@ -112,17 +111,13 @@ public class DefaultLoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthe if (HTTPMethod.valueOf(req.getMethod()) != HTTPMethod.POST) { throw new ServerApiException(ApiErrorCode.METHOD_NOT_ALLOWED, "Please use HTTP POST to authenticate using this API"); } + // FIXME: ported from ApiServlet, refactor and cleanup final String[] username = (String[])params.get(ApiConstants.USERNAME); final String[] password = (String[])params.get(ApiConstants.PASSWORD); - String[] domainIdArr = (String[])params.get(ApiConstants.DOMAIN_ID); - - if (domainIdArr == null) { - domainIdArr = (String[])params.get(ApiConstants.DOMAIN__ID); - } - final String[] domainName = (String[])params.get(ApiConstants.DOMAIN); + final String[] domainIdArr = (String[])params.get(ApiConstants.DOMAIN_ID); Long domainId = null; - if ((domainIdArr != null) && (domainIdArr.length > 0)) { + if (domainIdArr != null && domainIdArr.length > 0) { try { //check if UUID is passed in for domain domainId = _apiServer.fetchDomainId(domainIdArr[0]); @@ -140,6 +135,7 @@ public class DefaultLoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthe } String domain = null; + final String[] domainName = (String[])params.get(ApiConstants.DOMAIN); domain = getDomainName(auditTrailSb, domainName, domain); String serializedResponse = null; diff --git a/server/src/main/java/com/cloud/api/auth/DefaultResetPasswordAPIAuthenticatorCmd.java b/server/src/main/java/com/cloud/api/auth/DefaultResetPasswordAPIAuthenticatorCmd.java index 077efdee087..810b5ebefcf 100644 --- a/server/src/main/java/com/cloud/api/auth/DefaultResetPasswordAPIAuthenticatorCmd.java +++ b/server/src/main/java/com/cloud/api/auth/DefaultResetPasswordAPIAuthenticatorCmd.java @@ -53,7 +53,6 @@ import java.util.Map; responseObject = SuccessResponse.class) public class DefaultResetPasswordAPIAuthenticatorCmd extends BaseCmd implements APIAuthenticator { - ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// 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 3bd5fcba8e9..efda72555e2 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 @@ -272,7 +272,12 @@ public abstract class LibvirtServerDiscoverer extends DiscovererBase implements } } - sshConnection = new Connection(agentIp, 22); + int port = uri.getPort(); + if (port <= 0) { + port = AgentManager.KVMHostDiscoverySshPort.valueIn(clusterId); + } + + sshConnection = new Connection(agentIp, port); sshConnection.connect(null, 60000, 60000); @@ -380,6 +385,9 @@ public abstract class LibvirtServerDiscoverer extends DiscovererBase implements Map hostDetails = connectedHost.getDetails(); hostDetails.put("password", password); hostDetails.put("username", username); + if (uri.getPort() > 0) { + hostDetails.put(Host.HOST_SSH_PORT, String.valueOf(uri.getPort())); + } _hostDao.saveDetails(connectedHost); return resources; } catch (DiscoveredWithErrorException e) { diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index 0e1b7cdbc80..621b110486b 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -851,7 +851,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, _clusterDetailsDao.persist(cluster_cpu_detail); _clusterDetailsDao.persist(cluster_memory_detail); } - } uri = validatedHostUrl(url, hypervisorType); @@ -945,7 +944,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, hosts.add(host); } discoverer.postDiscovery(hosts, _nodeId); - } logger.info("server resources successfully discovered by " + discoverer.getName()); return hosts; @@ -3873,7 +3871,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, */ 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(), _agentMgr.getHostSshPort(host), 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/test/java/com/cloud/resource/ResourceManagerImplTest.java b/server/src/test/java/com/cloud/resource/ResourceManagerImplTest.java index 47472408404..3937a595069 100644 --- a/server/src/test/java/com/cloud/resource/ResourceManagerImplTest.java +++ b/server/src/test/java/com/cloud/resource/ResourceManagerImplTest.java @@ -387,12 +387,14 @@ public class ResourceManagerImplTest { @Test public void testConnectAndRestartAgentOnHost() { + when(agentManager.getHostSshPort(any())).thenReturn(22); resourceManager.connectAndRestartAgentOnHost(host, hostUsername, hostPassword, hostPrivateKey); } @Test public void testHandleAgentSSHEnabledNotConnectedAgent() { when(host.getStatus()).thenReturn(Status.Disconnected); + when(agentManager.getHostSshPort(any())).thenReturn(22); resourceManager.handleAgentIfNotConnected(host, false); verify(resourceManager).getHostCredentials(eq(host)); verify(resourceManager).connectAndRestartAgentOnHost(eq(host), eq(hostUsername), eq(hostPassword), eq(hostPrivateKey)); diff --git a/utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java b/utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java index dd1c17aa3c0..944f63391a9 100644 --- a/utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java +++ b/utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java @@ -77,7 +77,7 @@ public class SSHCmdHelper { } 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) {