diff --git a/.asf.yaml b/.asf.yaml index 43f0351bc7c..56c2a7c56c5 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -54,10 +54,11 @@ github: - gpordeus - hsato03 - bernardodemarco - - abh1sar - FelipeM525 - lucas-a-martins - nicoschmdt + - abh1sar + - sudo87 protected_branches: ~ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6d006938f3..17ff4badc97 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,9 +4,9 @@ Contributing to Apache CloudStack (ACS) Summary ------- This document covers how to contribute to the ACS project. ACS uses GitHub PRs to manage code contributions. -These instructions assume you have a GitHub.com account, so if you don't have one you will have to create one. Your proposed code changes will be published to your own fork of the ACS project and you will submit a Pull Request for your changes to be added. +These instructions assume you have a GitHub.com account, so if you don't have one you will have to create one. Your proposed code changes will be published to your own fork of the ACS project, and you will submit a Pull Request for your changes to be added. -_Lets get started!!!_ +_Let's get started!!!_ Bug fixes --------- @@ -26,7 +26,7 @@ No back porting / cherry-picking features to existing branches! PendingReleaseNotes file ------------------------ -When developing a new feature or making a (major) change to a existing feature you are encouraged to append this to the PendingReleaseNotes file so that the Release Manager can +When developing a new feature or making a (major) change to an existing feature you are encouraged to append this to the PendingReleaseNotes file so that the Release Manager can use this file as a source of information when compiling the Release Notes for a new release. When adding information to the PendingReleaseNotes file make sure that you write a good and understandable description of the new feature or change which you have developed. @@ -38,9 +38,9 @@ Fork the code In your browser, navigate to: [https://github.com/apache/cloudstack](https://github.com/apache/cloudstack) -Fork the repository by clicking on the 'Fork' button on the top right hand side. The fork will happen and you will be taken to your own fork of the repository. Copy the Git repository URL by clicking on the clipboard next to the URL on the right hand side of the page under '**HTTPS** clone URL'. You will paste this URL when doing the following `git clone` command. +Fork the repository by clicking on the 'Fork' button on the top right hand side. The fork will happen, and you will be taken to your own fork of the repository. Copy the Git repository URL by clicking on the clipboard next to the URL on the right hand side of the page under '**HTTPS** clone URL'. You will paste this URL when doing the following `git clone` command. -On your computer, follow these steps to setup a local repository for working on ACS: +On your computer, follow these steps to set up a local repository for working on ACS: ```bash $ git clone https://github.com/YOUR_ACCOUNT/cloudstack.git @@ -92,9 +92,9 @@ $ git rebase main Make a GitHub Pull Request to contribute your changes ----------------------------------------------------- -When you are happy with your changes and you are ready to contribute them, you will create a Pull Request on GitHub to do so. This is done by pushing your local changes to your forked repository (default remote name is `origin`) and then initiating a pull request on GitHub. +When you are happy with your changes, and you are ready to contribute them, you will create a Pull Request on GitHub to do so. This is done by pushing your local changes to your forked repository (default remote name is `origin`) and then initiating a pull request on GitHub. -Please include JIRA id, detailed information about the bug/feature, what all tests are executed, how the reviewer can test this feature etc. Incase of UI PRs, a screenshot is preferred. +Please include JIRA id, detailed information about the bug/feature, what all tests are executed, how the reviewer can test this feature etc. In case of UI PRs, a screenshot is preferred. > **IMPORTANT:** Make sure you have rebased your `feature_x` branch to include the latest code from `upstream/main` _before_ you do this. diff --git a/INSTALL.md b/INSTALL.md index e133e7d7b91..3685037bfe2 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -37,6 +37,7 @@ Setup up NodeJS (LTS): Start the MySQL service: $ service mysqld start + $ mysql_secure_installation ### Using jenv and/or pyenv for Version Management @@ -86,13 +87,33 @@ Start the management server: If this works, you've successfully setup a single server Apache CloudStack installation. -Open the following URL on your browser to access the Management Server UI: - - http://localhost:8080/client/ +To access the Management Server UI, follow the following procedure: The default credentials are; user: admin, password: password and the domain field should be left blank which is defaulted to the ROOT domain. +## To bring up CloudStack UI + +Move to UI Directory + + $ cd /path/to/cloudstack/ui + +To install dependencies. + + $ npm install + +To build the project. + + $ npm build + +For Development Mode. + + $ npm start + +Make sure to set CS_URL=http://localhost:8080/client on .env.local file on ui. + +You should be able to run the management server on http://localhost:5050 + ## Building with non-redistributable plugins CloudStack supports several plugins that depend on libraries with distribution restrictions. diff --git a/agent/bindir/cloud-setup-agent.in b/agent/bindir/cloud-setup-agent.in index 18de64089ed..9927c22eebc 100755 --- a/agent/bindir/cloud-setup-agent.in +++ b/agent/bindir/cloud-setup-agent.in @@ -20,6 +20,19 @@ import os import logging import sys import socket + +# ---- This snippet of code adds the sources path and the waf configured PYTHONDIR to the Python path ---- +# ---- We do this so cloud_utils can be looked up in the following order: +# ---- 1) Sources directory +# ---- 2) waf configured PYTHONDIR +# ---- 3) System Python path +for pythonpath in ( + "@PYTHONDIR@", + os.path.join(os.path.dirname(__file__),os.path.pardir,os.path.pardir,"python","lib"), + ): + if os.path.isdir(pythonpath): sys.path.insert(0,pythonpath) +# ---- End snippet of code ---- + from cloudutils.cloudException import CloudRuntimeException, CloudInternalException from cloudutils.utilities import initLoging, bash from cloudutils.configFileOps import configFileOps diff --git a/agent/bindir/libvirtqemuhook.in b/agent/bindir/libvirtqemuhook.in index e17944d8353..4cc6ed7a1d2 100755 --- a/agent/bindir/libvirtqemuhook.in +++ b/agent/bindir/libvirtqemuhook.in @@ -20,6 +20,19 @@ import sys import os import subprocess from threading import Timer + +# ---- This snippet of code adds the sources path and the waf configured PYTHONDIR to the Python path ---- +# ---- We do this so cloud_utils can be looked up in the following order: +# ---- 1) Sources directory +# ---- 2) waf configured PYTHONDIR +# ---- 3) System Python path +for pythonpath in ( + "@PYTHONDIR@", + os.path.join(os.path.dirname(__file__),os.path.pardir,os.path.pardir,"python","lib"), + ): + if os.path.isdir(pythonpath): sys.path.insert(0,pythonpath) +# ---- End snippet of code ---- + from xml.dom.minidom import parse from cloudutils.configFileOps import configFileOps from cloudutils.networkConfig import networkConfig diff --git a/agent/src/main/java/com/cloud/agent/Agent.java b/agent/src/main/java/com/cloud/agent/Agent.java index 0a76bfbb4f8..ad480fef4e5 100644 --- a/agent/src/main/java/com/cloud/agent/Agent.java +++ b/agent/src/main/java/com/cloud/agent/Agent.java @@ -342,7 +342,7 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater logger.info("Attempted to connect to the server, but received an unexpected exception, trying again...", e); } } - shell.updateConnectedHost(); + shell.updateConnectedHost(((NioClient)connection).getHost()); scavengeOldAgentObjects(); } @@ -617,15 +617,11 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater } protected void reconnect(final Link link) { - reconnect(link, null, null, false); + reconnect(link, null, false); } - protected void reconnect(final Link link, String preferredHost, List avoidHostList, boolean forTransfer) { + protected void reconnect(final Link link, String preferredMSHost, boolean forTransfer) { if (!(forTransfer || reconnectAllowed)) { - return; - } - - if (!reconnectAllowed) { logger.debug("Reconnect requested but it is not allowed {}", () -> getLinkLog(link)); return; } @@ -637,19 +633,26 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater serverResource.disconnected(); logger.info("Lost connection to host: {}. Attempting reconnection while we still have {} commands in progress.", shell.getConnectedHost(), commandsInProgress.get()); stopAndCleanupConnection(true); + String host = preferredMSHost; + if (org.apache.commons.lang3.StringUtils.isBlank(host)) { + host = shell.getNextHost(); + } + List avoidMSHostList = shell.getAvoidHosts(); do { - final String host = shell.getNextHost(); - connection = new NioClient(getAgentName(), host, shell.getPort(), shell.getWorkers(), shell.getSslHandshakeTimeout(), this); - logger.info("Reconnecting to host: {}", host); - try { - connection.start(); - } catch (final NioConnectionException e) { - logger.info("Attempted to re-connect to the server, but received an unexpected exception, trying again...", e); - stopAndCleanupConnection(false); + if (CollectionUtils.isEmpty(avoidMSHostList) || !avoidMSHostList.contains(host)) { + connection = new NioClient(getAgentName(), host, shell.getPort(), shell.getWorkers(), shell.getSslHandshakeTimeout(), this); + logger.info("Reconnecting to host: {}", host); + try { + connection.start(); + } catch (final NioConnectionException e) { + logger.info("Attempted to re-connect to the server, but received an unexpected exception, trying again...", e); + stopAndCleanupConnection(false); + } } shell.getBackoffAlgorithm().waitBeforeRetry(); + host = shell.getNextHost(); } while (!connection.isStartup()); - shell.updateConnectedHost(); + shell.updateConnectedHost(((NioClient)connection).getHost()); logger.info("Connected to the host: {}", shell.getConnectedHost()); } @@ -922,7 +925,7 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater return new SetupCertificateAnswer(true); } - private void processManagementServerList(final List msList, final String lbAlgorithm, final Long lbCheckInterval) { + private void processManagementServerList(final List msList, final List avoidMsList, final String lbAlgorithm, final Long lbCheckInterval) { if (CollectionUtils.isNotEmpty(msList) && StringUtils.isNotEmpty(lbAlgorithm)) { try { final String newMSHosts = String.format("%s%s%s", com.cloud.utils.StringUtils.toCSVList(msList), IAgentShell.hostLbAlgorithmSeparator, lbAlgorithm); @@ -934,6 +937,7 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater throw new CloudRuntimeException("Could not persist received management servers list", e); } } + shell.setAvoidHosts(avoidMsList); if ("shuffle".equals(lbAlgorithm)) { scheduleHostLBCheckerTask(0); } else { @@ -942,16 +946,18 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater } private Answer setupManagementServerList(final SetupMSListCommand cmd) { - processManagementServerList(cmd.getMsList(), cmd.getLbAlgorithm(), cmd.getLbCheckInterval()); + processManagementServerList(cmd.getMsList(), cmd.getAvoidMsList(), cmd.getLbAlgorithm(), cmd.getLbCheckInterval()); return new SetupMSListAnswer(true); } private Answer migrateAgentToOtherMS(final MigrateAgentConnectionCommand cmd) { try { if (CollectionUtils.isNotEmpty(cmd.getMsList())) { - processManagementServerList(cmd.getMsList(), cmd.getLbAlgorithm(), cmd.getLbCheckInterval()); + processManagementServerList(cmd.getMsList(), cmd.getAvoidMsList(), cmd.getLbAlgorithm(), cmd.getLbCheckInterval()); } - migrateAgentConnection(cmd.getAvoidMsList()); + Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("MigrateAgentConnection-Job")).schedule(() -> { + migrateAgentConnection(cmd.getAvoidMsList()); + }, 3, TimeUnit.SECONDS); } catch (Exception e) { String errMsg = "Migrate agent connection failed, due to " + e.getMessage(); logger.debug(errMsg, e); @@ -972,25 +978,26 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater throw new CloudRuntimeException("No other Management Server hosts to migrate"); } - String preferredHost = null; + String preferredMSHost = null; for (String msHost : msHostsList) { try (final Socket socket = new Socket()) { socket.connect(new InetSocketAddress(msHost, shell.getPort()), 5000); - preferredHost = msHost; + preferredMSHost = msHost; break; } catch (final IOException e) { throw new CloudRuntimeException("Management server host: " + msHost + " is not reachable, to migrate connection"); } } - if (preferredHost == null) { + if (preferredMSHost == null) { throw new CloudRuntimeException("Management server host(s) are not reachable, to migrate connection"); } - logger.debug("Management server host " + preferredHost + " is found to be reachable, trying to reconnect"); + logger.debug("Management server host " + preferredMSHost + " is found to be reachable, trying to reconnect"); shell.resetHostCounter(); + shell.setAvoidHosts(avoidMsList); shell.setConnectionTransfer(true); - reconnect(link, preferredHost, avoidMsList, true); + reconnect(link, preferredMSHost, true); } public void processResponse(final Response response, final Link link) { @@ -1003,14 +1010,21 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater for (final IAgentControlListener listener : controlListeners) { listener.processControlResponse(response, (AgentControlAnswer)answer); } - } else if (answer instanceof PingAnswer && (((PingAnswer) answer).isSendStartup()) && reconnectAllowed) { - logger.info("Management server requested startup command to reinitialize the agent"); - sendStartup(link); + } else if (answer instanceof PingAnswer) { + processPingAnswer((PingAnswer) answer); } else { updateLastPingResponseTime(); } } + private void processPingAnswer(final PingAnswer answer) { + if ((answer.isSendStartup()) && reconnectAllowed) { + logger.info("Management server requested startup command to reinitialize the agent"); + sendStartup(link); + } + shell.setAvoidHosts(answer.getAvoidMsList()); + } + public void processReadyCommand(final Command cmd) { final ReadyCommand ready = (ReadyCommand)cmd; // Set human readable sizes; @@ -1027,7 +1041,7 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater } verifyAgentArch(ready.getArch()); - processManagementServerList(ready.getMsHostList(), ready.getLbAlgorithm(), ready.getLbCheckInterval()); + processManagementServerList(ready.getMsHostList(), ready.getAvoidMsHostList(), ready.getLbAlgorithm(), ready.getLbCheckInterval()); logger.info("Ready command is processed for agent [id: {}, uuid: {}, name: {}]", getId(), getUuid(), getName()); } @@ -1374,26 +1388,26 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater if (msList == null || msList.length < 1) { return; } - final String preferredHost = msList[0]; + final String preferredMSHost = msList[0]; final String connectedHost = shell.getConnectedHost(); logger.debug("Running preferred host checker task, connected host={}, preferred host={}", - connectedHost, preferredHost); - if (preferredHost == null || preferredHost.equals(connectedHost) || link == null) { + connectedHost, preferredMSHost); + if (preferredMSHost == null || preferredMSHost.equals(connectedHost) || link == null) { return; } boolean isHostUp = false; try (final Socket socket = new Socket()) { - socket.connect(new InetSocketAddress(preferredHost, shell.getPort()), 5000); + socket.connect(new InetSocketAddress(preferredMSHost, shell.getPort()), 5000); isHostUp = true; } catch (final IOException e) { - logger.debug("Host: {} is not reachable", preferredHost); + logger.debug("Host: {} is not reachable", preferredMSHost); } if (isHostUp && link != null && commandsInProgress.get() == 0) { if (logger.isDebugEnabled()) { - logger.debug("Preferred host {} is found to be reachable, trying to reconnect", preferredHost); + logger.debug("Preferred host {} is found to be reachable, trying to reconnect", preferredMSHost); } shell.resetHostCounter(); - reconnect(link); + reconnect(link, preferredMSHost, false); } } catch (Throwable t) { logger.error("Error caught while attempting to connect to preferred host", t); diff --git a/agent/src/main/java/com/cloud/agent/AgentShell.java b/agent/src/main/java/com/cloud/agent/AgentShell.java index aea7fd3a8de..4862e7e001e 100644 --- a/agent/src/main/java/com/cloud/agent/AgentShell.java +++ b/agent/src/main/java/com/cloud/agent/AgentShell.java @@ -66,6 +66,7 @@ public class AgentShell implements IAgentShell, Daemon { private String _zone; private String _pod; private String _host; + private List _avoidHosts; private String _privateIp; private int _port; private int _proxyPort; @@ -76,7 +77,6 @@ public class AgentShell implements IAgentShell, Daemon { private volatile boolean _exit = false; private int _pingRetries; private final List _agents = new ArrayList(); - private String hostToConnect; private String connectedHost; private Long preferredHostCheckInterval; private boolean connectionTransfer = false; @@ -121,7 +121,7 @@ public class AgentShell implements IAgentShell, Daemon { if (_hostCounter >= hosts.length) { _hostCounter = 0; } - hostToConnect = hosts[_hostCounter % hosts.length]; + String hostToConnect = hosts[_hostCounter % hosts.length]; _hostCounter++; return hostToConnect; } @@ -143,11 +143,10 @@ public class AgentShell implements IAgentShell, Daemon { } @Override - public void updateConnectedHost() { - connectedHost = hostToConnect; + public void updateConnectedHost(String connectedHost) { + this.connectedHost = connectedHost; } - @Override public void resetHostCounter() { _hostCounter = 0; @@ -166,6 +165,16 @@ public class AgentShell implements IAgentShell, Daemon { } } + @Override + public void setAvoidHosts(List avoidHosts) { + _avoidHosts = avoidHosts; + } + + @Override + public List getAvoidHosts() { + return _avoidHosts; + } + @Override public String getPrivateIp() { return _privateIp; diff --git a/agent/src/main/java/com/cloud/agent/IAgentShell.java b/agent/src/main/java/com/cloud/agent/IAgentShell.java index c0ecd90ae69..9eefa6d2eee 100644 --- a/agent/src/main/java/com/cloud/agent/IAgentShell.java +++ b/agent/src/main/java/com/cloud/agent/IAgentShell.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.agent; +import java.util.List; import java.util.Map; import java.util.Properties; @@ -63,9 +64,13 @@ public interface IAgentShell { String[] getHosts(); + void setAvoidHosts(List hosts); + + List getAvoidHosts(); + long getLbCheckerInterval(Long receivedLbInterval); - void updateConnectedHost(); + void updateConnectedHost(String connectedHost); String getConnectedHost(); diff --git a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java index 61cd27fff77..feb1845d84b 100644 --- a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java +++ b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java @@ -816,7 +816,7 @@ public class AgentProperties{ * Data type: Integer.
* Default value: null */ - public static final Property SSL_HANDSHAKE_TIMEOUT = new Property<>("ssl.handshake.timeout", null, Integer.class); + public static final Property SSL_HANDSHAKE_TIMEOUT = new Property<>("ssl.handshake.timeout", 30, Integer.class); public static class Property { private String name; diff --git a/agent/src/test/java/com/cloud/agent/AgentShellTest.java b/agent/src/test/java/com/cloud/agent/AgentShellTest.java index 6d9758cc3dc..d8def24a603 100644 --- a/agent/src/test/java/com/cloud/agent/AgentShellTest.java +++ b/agent/src/test/java/com/cloud/agent/AgentShellTest.java @@ -358,7 +358,7 @@ public class AgentShellTest { AgentShell shell = new AgentShell(); shell.setHosts("test"); shell.getNextHost(); - shell.updateConnectedHost(); + shell.updateConnectedHost("test"); Assert.assertEquals(expected, shell.getConnectedHost()); } diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index 2ba27482b99..08d452d0de2 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -741,6 +741,13 @@ public class EventTypes { //Purge resources public static final String EVENT_PURGE_EXPUNGED_RESOURCES = "PURGE.EXPUNGED.RESOURCES"; + // Management Server + public static final String EVENT_MS_MAINTENANCE_PREPARE = "MS.MAINTENANCE.PREPARE"; + public static final String EVENT_MS_MAINTENANCE_CANCEL = "MS.MAINTENANCE.CANCEL"; + public static final String EVENT_MS_SHUTDOWN_PREPARE = "MS.SHUTDOWN.PREPARE"; + public static final String EVENT_MS_SHUTDOWN_CANCEL = "MS.SHUTDOWN.CANCEL"; + public static final String EVENT_MS_SHUTDOWN = "MS.SHUTDOWN"; + // OBJECT STORE public static final String EVENT_OBJECT_STORE_CREATE = "OBJECT.STORE.CREATE"; public static final String EVENT_OBJECT_STORE_DELETE = "OBJECT.STORE.DELETE"; @@ -1235,6 +1242,12 @@ public class EventTypes { entityEventDetails.put(EVENT_UPDATE_IMAGE_STORE_ACCESS_STATE, ImageStore.class); entityEventDetails.put(EVENT_LIVE_PATCH_SYSTEMVM, "SystemVMs"); + entityEventDetails.put(EVENT_MS_MAINTENANCE_PREPARE, "ManagementServer"); + entityEventDetails.put(EVENT_MS_MAINTENANCE_CANCEL, "ManagementServer"); + entityEventDetails.put(EVENT_MS_SHUTDOWN_PREPARE, "ManagementServer"); + entityEventDetails.put(EVENT_MS_SHUTDOWN_CANCEL, "ManagementServer"); + entityEventDetails.put(EVENT_MS_SHUTDOWN, "ManagementServer"); + //Object Store entityEventDetails.put(EVENT_OBJECT_STORE_CREATE, ObjectStore.class); entityEventDetails.put(EVENT_OBJECT_STORE_UPDATE, ObjectStore.class); diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 9840c747afc..e0dacfce2bb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -1171,6 +1171,7 @@ public class ApiConstants { public static final String PENDING_JOBS_COUNT = "pendingjobscount"; public static final String AGENTS_COUNT = "agentscount"; public static final String AGENTS = "agents"; + public static final String LAST_AGENTS = "lastagents"; public static final String PUBLIC_MTU = "publicmtu"; public static final String PRIVATE_MTU = "privatemtu"; diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiErrorCode.java b/api/src/main/java/org/apache/cloudstack/api/ApiErrorCode.java index d4fdeddc9a9..03dc37325d4 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiErrorCode.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiErrorCode.java @@ -30,6 +30,7 @@ public enum ApiErrorCode { UNSUPPORTED_ACTION_ERROR(432), API_LIMIT_EXCEED(429), + SERVICE_UNAVAILABLE(503), INTERNAL_ERROR(530), ACCOUNT_ERROR(531), ACCOUNT_RESOURCE_LIMIT_ERROR(532), diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java index 50e1798112d..ac180b6d456 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java @@ -41,6 +41,7 @@ import org.apache.cloudstack.api.response.ResourceIconResponse; import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.TemplateResponse; +import org.apache.cloudstack.api.response.UserDataResponse; import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VpcResponse; @@ -149,6 +150,9 @@ public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements @Parameter(name = ApiConstants.USER_DATA, type = CommandType.BOOLEAN, description = "Whether to return the VMs' user data or not. By default, user data will not be returned.", since = "4.18.0.0") private Boolean showUserData; + @Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, required = false, description = "the instances by userdata", since = "4.20.1") + private Long userdataId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -243,6 +247,10 @@ public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements return CollectionUtils.isEmpty(viewDetails); } + public Long getUserdataId() { + return userdataId; + } + public EnumSet getDetails() throws InvalidParameterValueException { if (isViewDetailsEmpty()) { if (_queryService.ReturnVmStatsOnVmList.value()) { diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java index 729fb5ff3bc..e6cad482fe5 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java @@ -82,6 +82,14 @@ public class ManagementServerResponse extends BaseResponse { @Param(description = "the Management Server Peers") private List peers; + @SerializedName(ApiConstants.LAST_AGENTS) + @Param(description = "the last agents this Management Server is responsible for, before shutdown or preparing for maintenance", since = "4.21.0.0") + private List lastAgents; + + @SerializedName(ApiConstants.AGENTS) + @Param(description = "the agents this Management Server is responsible for", since = "4.21.0.0") + private List agents; + @SerializedName(ApiConstants.AGENTS_COUNT) @Param(description = "the number of host agents this Management Server is responsible for", since = "4.21.0.0") private Long agentsCount; @@ -134,6 +142,14 @@ public class ManagementServerResponse extends BaseResponse { return ipAddress; } + public List getLastAgents() { + return lastAgents; + } + + public List getAgents() { + return agents; + } + public Long getAgentsCount() { return this.agentsCount; } @@ -190,6 +206,14 @@ public class ManagementServerResponse extends BaseResponse { this.ipAddress = ipAddress; } + public void setLastAgents(List lastAgents) { + this.lastAgents = lastAgents; + } + + public void setAgents(List agents) { + this.agents = agents; + } + public void setAgentsCount(Long agentsCount) { this.agentsCount = agentsCount; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java index db811ffbe2d..a1ffda72234 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java @@ -28,12 +28,11 @@ import org.apache.cloudstack.api.BaseResponseWithAssociatedNetwork; import org.apache.cloudstack.api.EntityReference; import com.cloud.network.Network; -import com.cloud.projects.ProjectAccount; import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; @SuppressWarnings("unused") -@EntityReference(value = {Network.class, ProjectAccount.class}) +@EntityReference(value = {Network.class}) public class NetworkResponse extends BaseResponseWithAssociatedNetwork implements ControlledEntityResponse, SetResourceIconResponse { @SerializedName(ApiConstants.ID) diff --git a/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java index 676803ea86b..51efb6d42cb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java @@ -149,6 +149,10 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations { @Param(description = "whether this pool is managed or not") private Boolean managed; + @SerializedName(ApiConstants.DETAILS) + @Param(description = "the storage pool details") + private Map details; + public Map getCaps() { return caps; } @@ -407,4 +411,12 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations { public void setManaged(Boolean managed) { this.managed = managed; } + + public Map getDetails() { + return details; + } + + public void setDetails(Map details) { + this.details = details; + } } diff --git a/client/bindir/cloud-setup-management.in b/client/bindir/cloud-setup-management.in index 70e727b40b2..84c87ae2e44 100755 --- a/client/bindir/cloud-setup-management.in +++ b/client/bindir/cloud-setup-management.in @@ -16,13 +16,27 @@ # specific language governing permissions and limitations # under the License. +import os import sys +# ---- This snippet of code adds the sources path and the waf configured PYTHONDIR to the Python path ---- +# ---- We do this so cloud_utils can be looked up in the following order: +# ---- 1) Sources directory +# ---- 2) waf configured PYTHONDIR +# ---- 3) System Python path +for pythonpath in ( + "@PYTHONDIR@", + os.path.join(os.path.dirname(__file__),os.path.pardir,os.path.pardir,"python","lib"), + ): + if os.path.isdir(pythonpath): sys.path.insert(0,pythonpath) +# ---- End snippet of code ---- + from cloudutils.syscfg import sysConfigFactory from cloudutils.utilities import initLoging, UnknownSystemException from cloudutils.cloudException import CloudRuntimeException, CloudInternalException from cloudutils.globalEnv import globalEnv from cloudutils.serviceConfigServer import cloudManagementConfig from optparse import OptionParser + if __name__ == '__main__': initLoging("@MSLOGDIR@/setupManagement.log") glbEnv = globalEnv() diff --git a/core/src/main/java/com/cloud/agent/api/PingAnswer.java b/core/src/main/java/com/cloud/agent/api/PingAnswer.java index 6353b121583..3a40ad3925f 100644 --- a/core/src/main/java/com/cloud/agent/api/PingAnswer.java +++ b/core/src/main/java/com/cloud/agent/api/PingAnswer.java @@ -19,18 +19,22 @@ package com.cloud.agent.api; +import java.util.List; + public class PingAnswer extends Answer { private PingCommand _command = null; private boolean sendStartup = false; + private List avoidMsList; protected PingAnswer() { } - public PingAnswer(PingCommand cmd, boolean sendStartup) { + public PingAnswer(PingCommand cmd, List avoidMsList, boolean sendStartup) { super(cmd); _command = cmd; this.sendStartup = sendStartup; + this.avoidMsList = avoidMsList; } public PingCommand getCommand() { @@ -44,4 +48,8 @@ public class PingAnswer extends Answer { public void setSendStartup(boolean sendStartup) { this.sendStartup = sendStartup; } + + public List getAvoidMsList() { + return avoidMsList; + } } diff --git a/core/src/main/java/com/cloud/agent/api/ReadyCommand.java b/core/src/main/java/com/cloud/agent/api/ReadyCommand.java index e2d974e3878..49768297ad5 100644 --- a/core/src/main/java/com/cloud/agent/api/ReadyCommand.java +++ b/core/src/main/java/com/cloud/agent/api/ReadyCommand.java @@ -35,6 +35,7 @@ public class ReadyCommand extends Command { private String hostUuid; private String hostName; private List msHostList; + private List avoidMsHostList; private String lbAlgorithm; private Long lbCheckInterval; private Boolean enableHumanReadableSizes; @@ -90,6 +91,14 @@ public class ReadyCommand extends Command { this.msHostList = msHostList; } + public List getAvoidMsHostList() { + return avoidMsHostList; + } + + public void setAvoidMsHostList(List msHostList) { + this.avoidMsHostList = avoidMsHostList; + } + public String getLbAlgorithm() { return lbAlgorithm; } diff --git a/core/src/main/java/org/apache/cloudstack/agent/lb/SetupMSListCommand.java b/core/src/main/java/org/apache/cloudstack/agent/lb/SetupMSListCommand.java index 50cf956c9e7..32f436434c1 100644 --- a/core/src/main/java/org/apache/cloudstack/agent/lb/SetupMSListCommand.java +++ b/core/src/main/java/org/apache/cloudstack/agent/lb/SetupMSListCommand.java @@ -26,12 +26,14 @@ import com.cloud.agent.api.Command; public class SetupMSListCommand extends Command { private List msList; + private List avoidMsList; private String lbAlgorithm; private Long lbCheckInterval; - public SetupMSListCommand(final List msList, final String lbAlgorithm, final Long lbCheckInterval) { + public SetupMSListCommand(final List msList, final List avoidMsList, final String lbAlgorithm, final Long lbCheckInterval) { super(); this.msList = msList; + this.avoidMsList = avoidMsList; this.lbAlgorithm = lbAlgorithm; this.lbCheckInterval = lbCheckInterval; } @@ -40,6 +42,10 @@ public class SetupMSListCommand extends Command { return msList; } + public List getAvoidMsList() { + return avoidMsList; + } + public String getLbAlgorithm() { return lbAlgorithm; } 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 82e2d29f407..c01345ca21b 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 @@ -16,7 +16,6 @@ // under the License. package com.cloud.agent; -import java.util.List; import java.util.Map; import org.apache.cloudstack.framework.config.ConfigKey; @@ -173,8 +172,4 @@ public interface AgentManager { void propagateChangeToAgents(Map params); boolean transferDirectAgentsFromMS(String fromMsUuid, long fromMsId, long timeoutDurationInMs); - - List getLastAgents(); - - void setLastAgents(List lastAgents); } 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 ca56446631c..6d4bcb7b0d9 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 @@ -214,13 +214,13 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl protected final ConfigKey Workers = new ConfigKey<>("Advanced", Integer.class, "workers", "5", "Number of worker threads handling remote agent connections.", false); - protected final ConfigKey Port = new ConfigKey<>("Advanced", Integer.class, "port", "8250", "Port to listen on for remote agent connections.", false); + protected final ConfigKey Port = new ConfigKey<>("Advanced", Integer.class, "port", "8250", "Port to listen on for remote (indirect) agent connections.", false); protected final ConfigKey RemoteAgentSslHandshakeTimeout = new ConfigKey<>("Advanced", Integer.class, "agent.ssl.handshake.timeout", "30", - "Seconds after which SSL handshake times out during remote agent connections.", false); + "Seconds after which SSL handshake times out during remote (indirect) agent connections.", false); protected final ConfigKey RemoteAgentMaxConcurrentNewConnections = new ConfigKey<>("Advanced", Integer.class, "agent.max.concurrent.new.connections", "0", - "Number of maximum concurrent new connections server allows for remote agents. " + + "Number of maximum concurrent new connections server allows for remote (indirect) agents. " + "If set to zero (default value) then no limit will be enforced on concurrent new connections", false); protected final ConfigKey AlertWait = new ConfigKey<>("Advanced", Integer.class, "alert.wait", "1800", @@ -255,9 +255,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl _executor = new ThreadPoolExecutor(agentTaskThreads, agentTaskThreads, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("AgentTaskPool")); - _connectExecutor = new ThreadPoolExecutor(100, 500, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("AgentConnectTaskPool")); - // allow core threads to time out even when there are no items in the queue - _connectExecutor.allowCoreThreadTimeOut(true); + initConnectExecutor(); maxConcurrentNewAgentConnections = RemoteAgentMaxConcurrentNewConnections.value(); @@ -273,10 +271,6 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl logger.debug("Created DirectAgentAttache pool with size: {}.", directAgentPoolSize); _directAgentThreadCap = Math.round(directAgentPoolSize * DirectAgentThreadCap.value()) + 1; // add 1 to always make the value > 0 - _monitorExecutor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("AgentMonitor")); - - newAgentConnectionsMonitor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("NewAgentConnectionsMonitor")); - initializeCommandTimeouts(); return true; @@ -351,10 +345,27 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl _hostMonitors.remove(id); } + @Override + public void onManagementServerPreparingForMaintenance() { + logger.debug("Management server preparing for maintenance"); + if (_connection != null) { + _connection.block(); + } + } + + @Override + public void onManagementServerCancelPreparingForMaintenance() { + logger.debug("Management server cancel preparing for maintenance"); + if (_connection != null) { + _connection.unblock(); + } + } + @Override public void onManagementServerMaintenance() { logger.debug("Management server maintenance enabled"); _monitorExecutor.shutdownNow(); + newAgentConnectionsMonitor.shutdownNow(); if (_connection != null) { _connection.stop(); @@ -371,10 +382,8 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl public void onManagementServerCancelMaintenance() { logger.debug("Management server maintenance disabled"); if (_connectExecutor.isShutdown()) { - _connectExecutor = new ThreadPoolExecutor(100, 500, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("AgentConnectTaskPool")); - _connectExecutor.allowCoreThreadTimeOut(true); + initConnectExecutor(); } - startDirectlyConnectedHosts(true); if (_connection != null) { try { @@ -385,9 +394,28 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl } if (_monitorExecutor.isShutdown()) { - _monitorExecutor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("AgentMonitor")); - _monitorExecutor.scheduleWithFixedDelay(new MonitorTask(), mgmtServiceConf.getPingInterval(), mgmtServiceConf.getPingInterval(), TimeUnit.SECONDS); + initAndScheduleMonitorExecutor(); } + if (newAgentConnectionsMonitor.isShutdown()) { + initAndScheduleAgentConnectionsMonitor(); + } + } + + private void initConnectExecutor() { + _connectExecutor = new ThreadPoolExecutor(100, 500, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("AgentConnectTaskPool")); + // allow core threads to time out even when there are no items in the queue + _connectExecutor.allowCoreThreadTimeOut(true); + } + + private void initAndScheduleMonitorExecutor() { + _monitorExecutor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("AgentMonitor")); + _monitorExecutor.scheduleWithFixedDelay(new MonitorTask(), mgmtServiceConf.getPingInterval(), mgmtServiceConf.getPingInterval(), TimeUnit.SECONDS); + } + + private void initAndScheduleAgentConnectionsMonitor() { + final int cleanupTimeInSecs = Wait.value(); + newAgentConnectionsMonitor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("NewAgentConnectionsMonitor")); + newAgentConnectionsMonitor.scheduleAtFixedRate(new AgentNewConnectionsMonitorTask(), cleanupTimeInSecs, cleanupTimeInSecs, TimeUnit.SECONDS); } private AgentControlAnswer handleControlCommand(final AgentAttache attache, final AgentControlCommand cmd) { @@ -426,16 +454,6 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl return attache; } - @Override - public List getLastAgents() { - return lastAgents; - } - - @Override - public void setLastAgents(List lastAgents) { - this.lastAgents = lastAgents; - } - @Override public Answer sendTo(final Long dcId, final HypervisorType type, final Command cmd) { final List clusters = _clusterDao.listByDcHyType(dcId, type.toString()); @@ -779,6 +797,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl ManagementServerHostVO msHost = _mshostDao.findByMsid(_nodeId); if (msHost != null && (ManagementServerHost.State.Maintenance.equals(msHost.getState()) || ManagementServerHost.State.PreparingForMaintenance.equals(msHost.getState()))) { _monitorExecutor.shutdownNow(); + newAgentConnectionsMonitor.shutdownNow(); return true; } @@ -792,12 +811,8 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl } } - _monitorExecutor.scheduleWithFixedDelay(new MonitorTask(), mgmtServiceConf.getPingInterval(), mgmtServiceConf.getPingInterval(), TimeUnit.SECONDS); - - final int cleanupTime = Wait.value(); - newAgentConnectionsMonitor.scheduleAtFixedRate(new AgentNewConnectionsMonitorTask(), cleanupTime, - cleanupTime, TimeUnit.MINUTES); - + initAndScheduleMonitorExecutor(); + initAndScheduleAgentConnectionsMonitor(); return true; } @@ -1304,6 +1319,8 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl if (!indirectAgentLB.compareManagementServerList(host.getId(), host.getDataCenterId(), agentMSHostList, lbAlgorithm)) { final List newMSList = indirectAgentLB.getManagementServerList(host.getId(), host.getDataCenterId(), null); ready.setMsHostList(newMSList); + final List avoidMsList = _mshostDao.listNonUpStateMsIPs(); + ready.setAvoidMsHostList(avoidMsList); ready.setLbAlgorithm(indirectAgentLB.getLBAlgorithmName()); ready.setLbCheckInterval(indirectAgentLB.getLBPreferredHostCheckInterval(host.getClusterId())); logger.debug("Agent's management server host list is not up to date, sending list update: {}", newMSList); @@ -1608,7 +1625,8 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl if (host!= null && host.getStatus() != Status.Up && gatewayAccessible) { requestStartupCommand = true; } - answer = new PingAnswer((PingCommand)cmd, requestStartupCommand); + final List avoidMsList = _mshostDao.listNonUpStateMsIPs(); + answer = new PingAnswer((PingCommand)cmd, avoidMsList, requestStartupCommand); } else if (cmd instanceof ReadyAnswer) { final HostVO host = _hostDao.findById(attache.getId()); if (host == null) { @@ -1929,25 +1947,19 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl logger.trace("Agent New Connections Monitor is started."); final int cleanupTime = Wait.value(); Set> entrySet = newAgentConnections.entrySet(); - long cutOff = System.currentTimeMillis() - (cleanupTime * 60 * 1000L); - if (logger.isDebugEnabled()) { - List expiredConnections = newAgentConnections.entrySet() - .stream() - .filter(e -> e.getValue() <= cutOff) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); - logger.debug("Currently {} active new connections, of which {} have expired - {}", - entrySet.size(), - expiredConnections.size(), - StringUtils.join(expiredConnections)); - } - for (Map.Entry entry : entrySet) { - if (entry.getValue() <= cutOff) { - if (logger.isTraceEnabled()) { - logger.trace("Cleaning up new agent connection for {}", entry.getKey()); - } - newAgentConnections.remove(entry.getKey()); - } + long cutOff = System.currentTimeMillis() - (cleanupTime * 1000L); + List expiredConnections = newAgentConnections.entrySet() + .stream() + .filter(e -> e.getValue() <= cutOff) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + logger.debug("Currently {} active new connections, of which {} have expired - {}", + entrySet.size(), + expiredConnections.size(), + StringUtils.join(expiredConnections)); + for (String connection : expiredConnections) { + logger.trace("Cleaning up new agent connection for {}", connection); + newAgentConnections.remove(connection); } } } diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java index c667df5412e..dad7d401b94 100644 --- a/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java @@ -151,11 +151,11 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust super(); } - protected final ConfigKey EnableLB = new ConfigKey<>(Boolean.class, "agent.lb.enabled", "Advanced", "false", "Enable agent load balancing between management server nodes", true); + protected final ConfigKey EnableLB = new ConfigKey<>(Boolean.class, "agent.lb.enabled", "Advanced", "false", "Enable direct agents load balancing between management server nodes", true); protected final ConfigKey ConnectedAgentThreshold = new ConfigKey<>(Double.class, "agent.load.threshold", "Advanced", "0.7", - "What percentage of the agents can be held by one management server before load balancing happens", true, EnableLB.key()); - protected final ConfigKey LoadSize = new ConfigKey<>(Integer.class, "direct.agent.load.size", "Advanced", "16", "How many agents to connect to in each round", true); - protected final ConfigKey ScanInterval = new ConfigKey<>(Integer.class, "direct.agent.scan.interval", "Advanced", "90", "Interval between scans to load agents", false, + "What percentage of the direct agents can be held by one management server before load balancing happens", true, EnableLB.key()); + protected final ConfigKey LoadSize = new ConfigKey<>(Integer.class, "direct.agent.load.size", "Advanced", "16", "How many direct agents to connect to in each round", true); + protected final ConfigKey ScanInterval = new ConfigKey<>(Integer.class, "direct.agent.scan.interval", "Advanced", "90", "Interval between scans to load direct agents", false, ConfigKey.Scope.Global, 1000); @Override @@ -1395,7 +1395,7 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust return false; } - long transferStartTime = System.currentTimeMillis(); + long transferStartTimeInMs = System.currentTimeMillis(); if (CollectionUtils.isEmpty(getDirectAgentHosts(fromMsId))) { logger.info("No direct agent hosts available on management server node {} (id: {}), to transfer", fromMsId, fromMsUuid); return true; @@ -1417,7 +1417,7 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust } logger.debug("Transferring {} direct agents from management server node {} (id: {}) of zone {}", directAgentHostsInDc.size(), fromMsId, fromMsUuid, dc); for (HostVO host : directAgentHostsInDc) { - long transferElapsedTimeInMs = System.currentTimeMillis() - transferStartTime; + long transferElapsedTimeInMs = System.currentTimeMillis() - transferStartTimeInMs; if (transferElapsedTimeInMs >= timeoutDurationInMs) { logger.debug("Stop transferring remaining direct agents from management server node {} (id: {}), timed out", fromMsId, fromMsUuid); return false; @@ -1486,6 +1486,18 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust } } + @Override + public void onManagementServerPreparingForMaintenance() { + logger.debug("Management server preparing for maintenance"); + super.onManagementServerPreparingForMaintenance(); + } + + @Override + public void onManagementServerCancelPreparingForMaintenance() { + logger.debug("Management server cancel preparing for maintenance"); + super.onManagementServerPreparingForMaintenance(); + } + @Override public void onManagementServerMaintenance() { logger.debug("Management server maintenance enabled"); diff --git a/engine/schema/src/main/java/com/cloud/configuration/ManagementServiceConfiguration.java b/engine/schema/src/main/java/com/cloud/configuration/ManagementServiceConfiguration.java index 51b7f62f56d..841447de5fd 100644 --- a/engine/schema/src/main/java/com/cloud/configuration/ManagementServiceConfiguration.java +++ b/engine/schema/src/main/java/com/cloud/configuration/ManagementServiceConfiguration.java @@ -21,7 +21,7 @@ import org.apache.cloudstack.framework.config.Configurable; public interface ManagementServiceConfiguration extends Configurable { ConfigKey PingInterval = new ConfigKey("Advanced", Integer.class, "ping.interval", "60", - "Interval to send application level pings to make sure the connection is still working", false); + "Interval in seconds to send application level pings to make sure the connection is still working", false); ConfigKey PingTimeout = new ConfigKey("Advanced", Float.class, "ping.timeout", "2.5", "Multiplier to ping.interval before announcing an agent has timed out", true); public int getPingInterval(); diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java index cfd75b1a94b..d44e842db8b 100644 --- a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java +++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java @@ -183,6 +183,13 @@ public interface HostDao extends GenericDao, StateDao listByMs(long msId); + /** + * Retrieves the last host ids/agents this {@see ManagementServer} has responsibility over. + * @param msId the id of the {@see ManagementServer} + * @return the last host ids/agents this {@see ManagementServer} has responsibility over + */ + List listByLastMs(long msId); + /** * Retrieves the hypervisor versions of the hosts in the datacenter which are in Up state in ascending order * @param datacenterId data center id @@ -200,7 +207,7 @@ public interface HostDao extends GenericDao, StateDao findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(final Long zoneId, final Long clusterId, - final List resourceStates, final List types, + final Long msId, final List resourceStates, final List types, final List hypervisorTypes); List listDistinctHypervisorTypes(final Long zoneId); diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java index 54146e55049..fac895400f3 100644 --- a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java @@ -129,6 +129,7 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao protected SearchBuilder ResponsibleMsSearch; protected SearchBuilder ResponsibleMsDcSearch; protected GenericSearchBuilder ResponsibleMsIdSearch; + protected GenericSearchBuilder LastMsIdSearch; protected SearchBuilder HostTypeClusterCountSearch; protected SearchBuilder HostTypeZoneCountSearch; protected SearchBuilder ClusterStatusSearch; @@ -209,6 +210,11 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao ResponsibleMsIdSearch.and("managementServerId", ResponsibleMsIdSearch.entity().getManagementServerId(), SearchCriteria.Op.EQ); ResponsibleMsIdSearch.done(); + LastMsIdSearch = createSearchBuilder(String.class); + LastMsIdSearch.selectFields(LastMsIdSearch.entity().getUuid()); + LastMsIdSearch.and("lastManagementServerId", LastMsIdSearch.entity().getLastManagementServerId(), SearchCriteria.Op.EQ); + LastMsIdSearch.done(); + HostTypeClusterCountSearch = createSearchBuilder(); HostTypeClusterCountSearch.and("cluster", HostTypeClusterCountSearch.entity().getClusterId(), SearchCriteria.Op.EQ); HostTypeClusterCountSearch.and("type", HostTypeClusterCountSearch.entity().getType(), SearchCriteria.Op.EQ); @@ -1569,6 +1575,13 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao return customSearch(sc, null); } + @Override + public List listByLastMs(long msId) { + SearchCriteria sc = LastMsIdSearch.create(); + sc.addAnd("lastManagementServerId", SearchCriteria.Op.EQ, msId); + return customSearch(sc, null); + } + @Override public List listOrderedHostsHypervisorVersionsInDatacenter(long datacenterId, HypervisorType hypervisorType) { PreparedStatement pstmt; @@ -1745,13 +1758,15 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao } @Override - public List findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(final Long zoneId, final Long clusterId, + public List findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(final Long zoneId, + final Long clusterId, final Long managementServerId, final List resourceStates, final List types, final List hypervisorTypes) { GenericSearchBuilder sb = createSearchBuilder(Long.class); sb.selectFields(sb.entity().getId()); sb.and("zoneId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); sb.and("clusterId", sb.entity().getClusterId(), SearchCriteria.Op.EQ); + sb.and("msId", sb.entity().getManagementServerId(), SearchCriteria.Op.EQ); sb.and("resourceState", sb.entity().getResourceState(), SearchCriteria.Op.IN); sb.and("type", sb.entity().getType(), SearchCriteria.Op.IN); if (CollectionUtils.isNotEmpty(hypervisorTypes)) { @@ -1767,6 +1782,9 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao if (clusterId != null) { sc.setParameters("clusterId", clusterId); } + if (managementServerId != null) { + sc.setParameters("msId", managementServerId); + } if (CollectionUtils.isNotEmpty(hypervisorTypes)) { sc.setParameters("hypervisorTypes", hypervisorTypes.toArray()); } diff --git a/engine/schema/src/test/java/com/cloud/host/dao/HostDaoImplTest.java b/engine/schema/src/test/java/com/cloud/host/dao/HostDaoImplTest.java index 81163321c6b..8f41162f242 100644 --- a/engine/schema/src/test/java/com/cloud/host/dao/HostDaoImplTest.java +++ b/engine/schema/src/test/java/com/cloud/host/dao/HostDaoImplTest.java @@ -104,6 +104,7 @@ public class HostDaoImplTest { public void testFindHostIdsByZoneClusterResourceStateTypeAndHypervisorType() { Long zoneId = 1L; Long clusterId = 2L; + Long msId = 1L; List resourceStates = List.of(ResourceState.Enabled); List types = List.of(Host.Type.Routing); List hypervisorTypes = List.of(Hypervisor.HypervisorType.KVM); @@ -117,10 +118,11 @@ public class HostDaoImplTest { Mockito.doReturn(sb).when(hostDao).createSearchBuilder(Long.class); Mockito.doReturn(mockResults).when(hostDao).customSearch(Mockito.any(SearchCriteria.class), Mockito.any()); List hostIds = hostDao.findHostIdsByZoneClusterResourceStateTypeAndHypervisorType( - zoneId, clusterId, resourceStates, types, hypervisorTypes); + zoneId, clusterId, msId, resourceStates, types, hypervisorTypes); Assert.assertEquals(mockResults, hostIds); Mockito.verify(sc).setParameters("zoneId", zoneId); Mockito.verify(sc).setParameters("clusterId", clusterId); + Mockito.verify(sc).setParameters("msId", msId); Mockito.verify(sc).setParameters("resourceState", resourceStates.toArray()); Mockito.verify(sc).setParameters("type", types.toArray()); Mockito.verify(sc).setParameters("hypervisorTypes", hypervisorTypes.toArray()); diff --git a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImpl.java b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImpl.java index de3be809a05..959d63ed2b5 100644 --- a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImpl.java +++ b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImpl.java @@ -22,14 +22,16 @@ import java.util.List; import javax.inject.Inject; -import com.cloud.dc.dao.DataCenterDao; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.DeleteStoragePoolCommand; +import com.cloud.dc.dao.DataCenterDao; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -37,8 +39,12 @@ import com.cloud.resource.ResourceManager; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.template.TemplateManager; import com.cloud.utils.Pair; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -59,6 +65,10 @@ public class BasePrimaryDataStoreLifeCycleImpl { protected DataCenterDao zoneDao; @Inject protected StoragePoolHostDao storagePoolHostDao; + @Inject + private PrimaryDataStoreDao primaryDataStoreDao; + @Inject + private TemplateManager templateMgr; private List getPoolHostsList(ClusterScope clusterScope, HypervisorType hypervisorType) { List hosts; @@ -81,7 +91,7 @@ public class BasePrimaryDataStoreLifeCycleImpl { try { storageMgr.connectHostToSharedPool(host, store.getId()); } catch (Exception e) { - logger.warn("Unable to establish a connection between " + host + " and " + store, e); + logger.warn("Unable to establish a connection between {} and {}", host, store, e); } } } @@ -99,7 +109,7 @@ public class BasePrimaryDataStoreLifeCycleImpl { if (answer != null) { if (!answer.getResult()) { - logger.debug("Failed to delete storage pool: " + answer.getResult()); + logger.debug("Failed to delete storage pool: {}", answer.getResult()); } else if (HypervisorType.KVM != hypervisorType) { break; } @@ -108,4 +118,42 @@ public class BasePrimaryDataStoreLifeCycleImpl { } dataStoreHelper.switchToCluster(store, clusterScope); } + + private void evictTemplates(StoragePoolVO storagePoolVO) { + List unusedTemplatesInPool = templateMgr.getUnusedTemplatesInPool(storagePoolVO); + for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) { + if (templatePoolVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { + templateMgr.evictTemplateFromStoragePool(templatePoolVO); + } + } + } + + private void deleteAgentStoragePools(StoragePool storagePool) { + List poolHostVOs = storagePoolHostDao.listByPoolId(storagePool.getId()); + for (StoragePoolHostVO poolHostVO : poolHostVOs) { + DeleteStoragePoolCommand deleteStoragePoolCommand = new DeleteStoragePoolCommand(storagePool); + final Answer answer = agentMgr.easySend(poolHostVO.getHostId(), deleteStoragePoolCommand); + if (answer != null && answer.getResult()) { + logger.info("Successfully deleted storage pool: {} from host: {}", storagePool.getId(), poolHostVO.getHostId()); + } else { + if (answer != null) { + logger.error("Failed to delete storage pool: {} from host: {} , result: {}", storagePool.getId(), poolHostVO.getHostId(), answer.getResult()); + } else { + logger.error("Failed to delete storage pool: {} from host: {}", storagePool.getId(), poolHostVO.getHostId()); + } + } + } + } + + protected boolean cleanupDatastore(DataStore store) { + StoragePool storagePool = (StoragePool)store; + StoragePoolVO storagePoolVO = primaryDataStoreDao.findById(storagePool.getId()); + if (storagePoolVO == null) { + return false; + } + + evictTemplates(storagePoolVO); + deleteAgentStoragePools(storagePool); + return true; + } } diff --git a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java index 1afc1a68b44..331b1f3ce5b 100644 --- a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java +++ b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -43,7 +43,6 @@ import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StorageService; import com.cloud.storage.dao.StoragePoolHostDao; -import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -60,6 +59,7 @@ import javax.inject.Inject; import java.util.List; import java.util.Map; +import java.util.Optional; public class DefaultHostListener implements HypervisorHostListener { protected Logger logger = LogManager.getLogger(getClass()); @@ -133,9 +133,11 @@ public class DefaultHostListener implements HypervisorHostListener { @Override public boolean hostConnect(long hostId, long poolId) throws StorageConflictException { StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary); - Pair, Boolean> nfsMountOpts = storageManager.getStoragePoolNFSMountOpts(pool, null); + Map detailsMap = storagePoolDetailsDao.listDetailsKeyPairs(poolId); + Map nfsMountOpts = storageManager.getStoragePoolNFSMountOpts(pool, null).first(); - ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool, nfsMountOpts.first()); + Optional.ofNullable(nfsMountOpts).ifPresent(detailsMap::putAll); + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool, detailsMap); cmd.setWait(modifyStoragePoolCommandWait); HostVO host = hostDao.findById(hostId); logger.debug("Sending modify storage pool command to agent: {} for storage pool: {} with timeout {} seconds", host, pool, cmd.getWait()); diff --git a/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java b/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java index 1b45910b88a..d2c85b498f2 100644 --- a/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java +++ b/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java @@ -1107,9 +1107,19 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C if (_mshostId != null) { final ManagementServerHostVO mshost = _mshostDao.findByMsid(_msId); if (mshost != null) { - final ManagementServerStatusVO mshostStatus = mshostStatusDao.findByMsId(mshost.getUuid()); - mshostStatus.setLastJvmStop(new Date()); - mshostStatusDao.update(mshostStatus.getId(), mshostStatus); + ManagementServerStatusVO mshostStatus = mshostStatusDao.findByMsId(mshost.getUuid()); + if (mshostStatus != null) { + mshostStatus.setLastJvmStop(new Date()); + mshostStatusDao.update(mshostStatus.getId(), mshostStatus); + } else { + logger.warn("Found a management server host [{}] without a status. This should never happen!", mshost); + mshostStatus = new ManagementServerStatusVO(); + mshostStatus.setMsId(mshost.getUuid()); + mshostStatus.setLastSystemBoot(new Date()); + mshostStatus.setLastJvmStart(new Date()); + mshostStatus.setUpdated(new Date()); + mshostStatusDao.persist(mshostStatus); + } ManagementServerHost.State msHostState = ManagementServerHost.State.Down; if (ManagementServerHost.State.Maintenance.equals(mshost.getState()) || ManagementServerHost.State.PreparingForMaintenance.equals(mshost.getState())) { diff --git a/framework/config/src/main/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java b/framework/config/src/main/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java index b1c3c5d9a27..650c078a370 100644 --- a/framework/config/src/main/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java +++ b/framework/config/src/main/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java @@ -85,7 +85,7 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin { List _scopedStorages; Set _configured = Collections.synchronizedSet(new HashSet()); Set newConfigs = Collections.synchronizedSet(new HashSet<>()); - LazyCache configCache; + LazyCache, String> configCache; private HashMap>> _allKeys = new HashMap>>(1007); @@ -275,15 +275,10 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin { return _configDao; } - protected String getConfigStringValueInternal(String cacheKey) { - String[] parts = cacheKey.split("-"); - String key = parts[0]; - ConfigKey.Scope scope = ConfigKey.Scope.Global; - Long scopeId = null; - try { - scope = ConfigKey.Scope.valueOf(parts[1]); - scopeId = Long.valueOf(parts[2]); - } catch (IllegalArgumentException ignored) {} + protected String getConfigStringValueInternal(Ternary cacheKey) { + String key = cacheKey.first(); + ConfigKey.Scope scope = cacheKey.second(); + Long scopeId = cacheKey.third(); if (!ConfigKey.Scope.Global.equals(scope) && scopeId != null) { ScopedConfigStorage scopedConfigStorage = getScopedStorage(scope); if (scopedConfigStorage == null) { @@ -298,8 +293,8 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin { return null; } - private String getConfigCacheKey(String key, ConfigKey.Scope scope, Long scopeId) { - return String.format("%s-%s-%d", key, scope, (scopeId == null ? 0 : scopeId)); + protected Ternary getConfigCacheKey(String key, ConfigKey.Scope scope, Long scopeId) { + return new Ternary<>(key, scope, scopeId); } @Override diff --git a/framework/config/src/test/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImplTest.java b/framework/config/src/test/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImplTest.java index ed752165aeb..a6e62902e15 100644 --- a/framework/config/src/test/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImplTest.java +++ b/framework/config/src/test/java/org/apache/cloudstack/framework/config/impl/ConfigDepotImplTest.java @@ -89,6 +89,12 @@ public class ConfigDepotImplTest { runTestGetConfigStringValue("test", "value"); } + @Test + public void testGetConfigStringValue_nameWithCharacters() { + runTestGetConfigStringValue("test.1-1", "value"); + runTestGetConfigStringValue("test_1#2", "value"); + } + private void runTestGetConfigStringValueExpiry(long wait, int configDBRetrieval) { String key = "test1"; String value = "expiry"; diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java index 448a4eb219c..41af291bd69 100644 --- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java +++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java @@ -237,7 +237,7 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, } } - throw new CloudRuntimeException("Maintenance or Shutdown has been initiated on this management server. Can not accept new jobs"); + throw new CloudRuntimeException("Maintenance or Shutdown has been initiated on this management server. Can not accept new async jobs"); } private boolean checkSyncQueueItemAllowed(SyncQueueItemVO item) { diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/GenericPresetVariable.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/GenericPresetVariable.java index f59f23abdc1..7073d2760d7 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/GenericPresetVariable.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/GenericPresetVariable.java @@ -49,8 +49,12 @@ public class GenericPresetVariable { fieldNamesToIncludeInToString.add("name"); } + /*** + * Converts the preset variable into a valid JSON object that will be injected into the JS interpreter. + * This method should not be overridden or changed. + */ @Override - public String toString() { + public final String toString() { return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, fieldNamesToIncludeInToString.toArray(new String[0])); } } diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Resource.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Resource.java index b1dfbacbfcd..4f8a971b869 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Resource.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Resource.java @@ -40,8 +40,12 @@ public class Resource { this.domainId = domainId; } + /*** + * Converts the preset variable into a valid JSON object that will be injected into the JS interpreter. + * This method should not be overridden or changed. + */ @Override - public String toString() { + public final String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } diff --git a/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/VeeamBackupProvider.java b/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/VeeamBackupProvider.java index 0a013587f6f..93278e80851 100644 --- a/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/VeeamBackupProvider.java +++ b/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/VeeamBackupProvider.java @@ -191,6 +191,9 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider, public boolean removeVMFromBackupOffering(final VirtualMachine vm) { final VeeamClient client = getClient(vm.getDataCenterId()); final VmwareDatacenter vmwareDC = findVmwareDatacenterForVM(vm); + if (vm.getBackupExternalId() == null) { + throw new CloudRuntimeException("The VM does not have a backup job assigned."); + } try { if (!client.removeVMFromVeeamJob(vm.getBackupExternalId(), vm.getInstanceName(), vmwareDC.getVcenterHost())) { logger.warn("Failed to remove VM from Veeam Job id: " + vm.getBackupExternalId()); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCreatePrivateTemplateFromVolumeCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCreatePrivateTemplateFromVolumeCommandWrapper.java index de35a1251bb..9fb282866cb 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCreatePrivateTemplateFromVolumeCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCreatePrivateTemplateFromVolumeCommandWrapper.java @@ -108,9 +108,7 @@ public final class LibvirtCreatePrivateTemplateFromVolumeCommandWrapper extends } else { logger.debug("Converting RBD disk " + disk.getPath() + " into template " + command.getUniqueName()); - final QemuImgFile srcFile = - new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(primary.getSourceHost(), primary.getSourcePort(), primary.getAuthUserName(), - primary.getAuthSecret(), disk.getPath())); + final QemuImgFile srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(primary, disk.getPath())); srcFile.setFormat(PhysicalDiskFormat.RAW); final QemuImgFile destFile = new QemuImgFile(tmpltPath + "/" + command.getUniqueName() + ".qcow2"); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVolumesOnStorageCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVolumesOnStorageCommandWrapper.java index 821a80f5cca..0f0c6488bb3 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVolumesOnStorageCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVolumesOnStorageCommandWrapper.java @@ -161,11 +161,7 @@ public final class LibvirtGetVolumesOnStorageCommandWrapper extends CommandWrapp QemuImg qemu = new QemuImg(0); QemuImgFile qemuFile = new QemuImgFile(disk.getPath(), disk.getFormat()); if (StoragePoolType.RBD.equals(pool.getType())) { - String rbdDestFile = KVMPhysicalDisk.RBDStringBuilder(pool.getSourceHost(), - pool.getSourcePort(), - pool.getAuthUserName(), - pool.getAuthSecret(), - disk.getPath()); + String rbdDestFile = KVMPhysicalDisk.RBDStringBuilder(pool, disk.getPath()); qemuFile = new QemuImgFile(rbdDestFile, disk.getFormat()); } return qemu.info(qemuFile, secure); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java index 6185c69032f..ba689d5107f 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java @@ -410,9 +410,7 @@ public class IscsiAdmStorageAdaptor implements StorageAdaptor { KVMStoragePool srcPool = srcDisk.getPool(); if (srcPool.getType() == StoragePoolType.RBD) { - srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(srcPool.getSourceHost(), srcPool.getSourcePort(), - srcPool.getAuthUserName(), srcPool.getAuthSecret(), - srcDisk.getPath()),srcDisk.getFormat()); + srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(srcPool, srcDisk.getPath()), srcDisk.getFormat()); } else { srcFile = new QemuImgFile(srcDisk.getPath(), srcDisk.getFormat()); } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMPhysicalDisk.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMPhysicalDisk.java index 9d9a6415e27..ab02e16603d 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMPhysicalDisk.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMPhysicalDisk.java @@ -23,6 +23,7 @@ import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class KVMPhysicalDisk { private String path; @@ -32,10 +33,17 @@ public class KVMPhysicalDisk { private String vmName; private boolean useAsTemplate; - public static String RBDStringBuilder(String monHost, int monPort, String authUserName, String authSecret, String image) { - String rbdOpts; + public static final String RBD_DEFAULT_DATA_POOL = "rbd_default_data_pool"; - rbdOpts = "rbd:" + image; + public static String RBDStringBuilder(KVMStoragePool storagePool, String image) { + String monHost = storagePool.getSourceHost(); + int monPort = storagePool.getSourcePort(); + String authUserName = storagePool.getAuthUserName(); + String authSecret = storagePool.getAuthSecret(); + Map details = storagePool.getDetails(); + String dataPool = (details == null) ? null : details.get(RBD_DEFAULT_DATA_POOL); + + String rbdOpts = "rbd:" + image; rbdOpts += ":mon_host=" + composeOptionForMonHosts(monHost, monPort); if (authUserName == null) { @@ -46,6 +54,10 @@ public class KVMPhysicalDisk { rbdOpts += ":key=" + authSecret; } + if (dataPool != null) { + rbdOpts += String.format(":rbd_default_data_pool=%s", dataPool); + } + rbdOpts += ":rbd_default_format=2"; rbdOpts += ":client_mount_timeout=30"; 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 e27547acbb2..ed389a1cf73 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 @@ -53,28 +53,6 @@ import com.cloud.vm.VirtualMachine; public class KVMStoragePoolManager { protected Logger logger = LogManager.getLogger(getClass()); - private class StoragePoolInformation { - String name; - String host; - int port; - String path; - String userInfo; - boolean type; - StoragePoolType poolType; - Map details; - - public StoragePoolInformation(String name, String host, int port, String path, String userInfo, StoragePoolType poolType, Map details, boolean type) { - this.name = name; - this.host = host; - this.port = port; - this.path = path; - this.userInfo = userInfo; - this.type = type; - this.poolType = poolType; - this.details = details; - } - } - private KVMHAMonitor _haMonitor; private final Map _storagePools = new ConcurrentHashMap(); private final Map _storageMapper = new HashMap(); @@ -303,14 +281,33 @@ public class KVMStoragePoolManager { } catch (Exception e) { StoragePoolInformation info = _storagePools.get(uuid); if (info != null) { - pool = createStoragePool(info.name, info.host, info.port, info.path, info.userInfo, info.poolType, info.details, info.type); + pool = createStoragePool(info.getName(), info.getHost(), info.getPort(), info.getPath(), info.getUserInfo(), info.getPoolType(), info.getDetails(), info.isType()); } else { throw new CloudRuntimeException("Could not fetch storage pool " + uuid + " from libvirt due to " + e.getMessage()); } } + + if (pool instanceof LibvirtStoragePool) { + addPoolDetails(uuid, (LibvirtStoragePool) pool); + } + return pool; } + /** + * As the class {@link LibvirtStoragePool} is constrained to the {@link org.libvirt.StoragePool} class, there is no way of saving a generic parameter such as the details, hence, + * this method was created to always make available the details of libvirt primary storages for when they are needed. + */ + private void addPoolDetails(String uuid, LibvirtStoragePool pool) { + StoragePoolInformation storagePoolInformation = _storagePools.get(uuid); + Map details = storagePoolInformation.getDetails(); + + if (MapUtils.isNotEmpty(details)) { + logger.trace("Adding the details {} to the pool with UUID {}.", details, uuid); + pool.setDetails(details); + } + } + public KVMStoragePool getStoragePoolByURI(String uri) { URI storageUri = null; diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index cdb523a50fd..c35c7e9a62b 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -667,9 +667,7 @@ public class KVMStorageProcessor implements StorageProcessor { } else { logger.debug("Converting RBD disk " + disk.getPath() + " into template " + templateName); - final QemuImgFile srcFile = - new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(primary.getSourceHost(), primary.getSourcePort(), primary.getAuthUserName(), - primary.getAuthSecret(), disk.getPath())); + final QemuImgFile srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(primary, disk.getPath())); srcFile.setFormat(PhysicalDiskFormat.RAW); final QemuImgFile destFile = new QemuImgFile(tmpltPath + "/" + templateName + ".qcow2"); @@ -1022,9 +1020,7 @@ public class KVMStorageProcessor implements StorageProcessor { logger.debug("Attempting to create " + snapDir.getAbsolutePath() + " recursively for snapshot storage"); FileUtils.forceMkdir(snapDir); - final QemuImgFile srcFile = - new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(primaryPool.getSourceHost(), primaryPool.getSourcePort(), primaryPool.getAuthUserName(), - primaryPool.getAuthSecret(), rbdSnapshot)); + final QemuImgFile srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(primaryPool, rbdSnapshot)); srcFile.setFormat(snapshotDisk.getFormat()); final QemuImgFile destFile = new QemuImgFile(snapshotFile); 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 f3731459f89..e93f82ac4dd 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 @@ -960,17 +960,55 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { } } + /** + * Creates a physical disk depending on the {@link StoragePoolType}: + *
    + *
  • + * {@link StoragePoolType#RBD} + *
      + *
    • + * If it is an erasure code pool, utilizes QemuImg to create the physical disk through the method + * {@link LibvirtStorageAdaptor#createPhysicalDiskByQemuImg(String, KVMStoragePool, PhysicalDiskFormat, Storage.ProvisioningType, long, byte[])} + *
    • + *
    • + * Otherwise, utilize Libvirt to create the physical disk through the method + * {@link LibvirtStorageAdaptor#createPhysicalDiskByLibVirt(String, KVMStoragePool, PhysicalDiskFormat, Storage.ProvisioningType, long)} + *
    • + *
    + *
  • + *
  • + * {@link StoragePoolType#NetworkFilesystem} and {@link StoragePoolType#Filesystem} + *
      + *
    • + * If the format is {@link PhysicalDiskFormat#QCOW2} or {@link PhysicalDiskFormat#RAW}, utilizes QemuImg to create the physical disk through the method + * {@link LibvirtStorageAdaptor#createPhysicalDiskByQemuImg(String, KVMStoragePool, PhysicalDiskFormat, Storage.ProvisioningType, long, byte[])} + *
    • + *
    • + * If the format is {@link PhysicalDiskFormat#DIR} or {@link PhysicalDiskFormat#TAR}, utilize Libvirt to create the physical disk through the method + * {@link LibvirtStorageAdaptor#createPhysicalDiskByLibVirt(String, KVMStoragePool, PhysicalDiskFormat, Storage.ProvisioningType, long)} + *
    • + *
    + *
  • + *
  • + * For the rest of the {@link StoragePoolType} types, utilizes the Libvirt method + * {@link LibvirtStorageAdaptor#createPhysicalDiskByLibVirt(String, KVMStoragePool, PhysicalDiskFormat, Storage.ProvisioningType, long)} + *
  • + *
+ */ @Override public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, byte[] passphrase) { - logger.info("Attempting to create volume " + name + " (" + pool.getType().toString() + ") in pool " - + pool.getUuid() + " with size " + toHumanReadableSize(size)); + logger.info("Attempting to create volume {} ({}) in pool {} with size {}", name, pool.getType().toString(), pool.getUuid(), toHumanReadableSize(size)); StoragePoolType poolType = pool.getType(); - if (poolType.equals(StoragePoolType.RBD)) { - return createPhysicalDiskByLibVirt(name, pool, PhysicalDiskFormat.RAW, provisioningType, size); - } else if (poolType.equals(StoragePoolType.NetworkFilesystem) || poolType.equals(StoragePoolType.Filesystem)) { + if (StoragePoolType.RBD.equals(poolType)) { + Map details = pool.getDetails(); + String dataPool = (details == null) ? null : details.get(KVMPhysicalDisk.RBD_DEFAULT_DATA_POOL); + + return (dataPool == null) ? createPhysicalDiskByLibVirt(name, pool, PhysicalDiskFormat.RAW, provisioningType, size) : + createPhysicalDiskByQemuImg(name, pool, PhysicalDiskFormat.RAW, provisioningType, size, passphrase); + } else if (StoragePoolType.NetworkFilesystem.equals(poolType) || StoragePoolType.Filesystem.equals(poolType)) { switch (format) { case QCOW2: case RAW: @@ -1018,18 +1056,25 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { } - private KVMPhysicalDisk createPhysicalDiskByQemuImg(String name, KVMStoragePool pool, - PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, byte[] passphrase) { - String volPath = pool.getLocalPath() + "/" + name; + private KVMPhysicalDisk createPhysicalDiskByQemuImg(String name, KVMStoragePool pool, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, + byte[] passphrase) { + String volPath; String volName = name; long virtualSize = 0; long actualSize = 0; QemuObject.EncryptFormat encryptFormat = null; List passphraseObjects = new ArrayList<>(); - final int timeout = 0; + QemuImgFile destFile; + + if (StoragePoolType.RBD.equals(pool.getType())) { + volPath = pool.getSourceDir() + File.separator + name; + destFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(pool, volPath)); + } else { + volPath = pool.getLocalPath() + File.separator + name; + destFile = new QemuImgFile(volPath); + } - QemuImgFile destFile = new QemuImgFile(volPath); destFile.setFormat(format); destFile.setSize(size); Map options = new HashMap(); @@ -1312,11 +1357,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { QemuImgFile srcFile; - QemuImgFile destFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(destPool.getSourceHost(), - destPool.getSourcePort(), - destPool.getAuthUserName(), - destPool.getAuthSecret(), - disk.getPath())); + QemuImgFile destFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(destPool, disk.getPath())); destFile.setFormat(format); if (srcPool.getType() != StoragePoolType.RBD) { @@ -1591,11 +1632,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { try { srcFile = new QemuImgFile(sourcePath, sourceFormat); String rbdDestPath = destPool.getSourceDir() + "/" + name; - String rbdDestFile = KVMPhysicalDisk.RBDStringBuilder(destPool.getSourceHost(), - destPool.getSourcePort(), - destPool.getAuthUserName(), - destPool.getAuthSecret(), - rbdDestPath); + String rbdDestFile = KVMPhysicalDisk.RBDStringBuilder(destPool, rbdDestPath); destFile = new QemuImgFile(rbdDestFile, destFormat); logger.debug("Starting copy from source image " + srcFile.getFileName() + " to RBD image " + rbdDestPath); @@ -1638,9 +1675,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { We let Qemu-Img do the work here. Although we could work with librbd and have that do the cloning it doesn't benefit us. It's better to keep the current code in place which works */ - srcFile = - new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(srcPool.getSourceHost(), srcPool.getSourcePort(), srcPool.getAuthUserName(), srcPool.getAuthSecret(), - sourcePath)); + srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(srcPool, sourcePath)); srcFile.setFormat(sourceFormat); destFile = new QemuImgFile(destPath); destFile.setFormat(destFormat); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java index 8e5af7c613d..ab39f7bc6ff 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java @@ -56,8 +56,8 @@ public class LibvirtStoragePool implements KVMStoragePool { protected String authSecret; protected String sourceHost; protected int sourcePort; - protected String sourceDir; + protected Map details; public LibvirtStoragePool(String uuid, String name, StoragePoolType type, StorageAdaptor adaptor, StoragePool pool) { this.uuid = uuid; @@ -311,7 +311,11 @@ public class LibvirtStoragePool implements KVMStoragePool { @Override public Map getDetails() { - return null; + return this.details; + } + + public void setDetails(Map details) { + this.details = details; } @Override diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StoragePoolInformation.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StoragePoolInformation.java new file mode 100644 index 00000000000..f330c9f24f0 --- /dev/null +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StoragePoolInformation.java @@ -0,0 +1,75 @@ +// 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. +package com.cloud.hypervisor.kvm.storage; + +import com.cloud.storage.Storage; + +import java.util.Map; + +class StoragePoolInformation { + private String name; + private String host; + private int port; + private String path; + private String userInfo; + private boolean type; + private Storage.StoragePoolType poolType; + private Map details; + + public StoragePoolInformation(String name, String host, int port, String path, String userInfo, Storage.StoragePoolType poolType, Map details, boolean type) { + this.name = name; + this.host = host; + this.port = port; + this.path = path; + this.userInfo = userInfo; + this.type = type; + this.poolType = poolType; + this.details = details; + } + + public String getName() { + return name; + } + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + + public String getPath() { + return path; + } + + public String getUserInfo() { + return userInfo; + } + + public boolean isType() { + return type; + } + + public Storage.StoragePoolType getPoolType() { + return poolType; + } + + public Map getDetails() { + return details; + } +} diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/KVMPhysicalDiskTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/KVMPhysicalDiskTest.java index 187565c0602..098f3e1b8bd 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/KVMPhysicalDiskTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/KVMPhysicalDiskTest.java @@ -17,43 +17,73 @@ package com.cloud.hypervisor.kvm.storage; import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.Mockito; -import junit.framework.TestCase; import org.mockito.junit.MockitoJUnitRunner; - @RunWith(MockitoJUnitRunner.class) -public class KVMPhysicalDiskTest extends TestCase { +public class KVMPhysicalDiskTest { + @Mock + KVMStoragePool kvmStoragePoolMock; + + private final String authUserName = "admin"; + + private final String authSecret = "supersecret"; @Test public void testRBDStringBuilder() { - assertEquals(KVMPhysicalDisk.RBDStringBuilder("ceph-monitor", 8000, "admin", "supersecret", "volume1"), - "rbd:volume1:mon_host=ceph-monitor\\:8000:auth_supported=cephx:id=admin:key=supersecret:rbd_default_format=2:client_mount_timeout=30"); + String monHosts = "ceph-monitor"; + int monPort = 8000; + + Mockito.doReturn(monHosts).when(kvmStoragePoolMock).getSourceHost(); + Mockito.doReturn(monPort).when(kvmStoragePoolMock).getSourcePort(); + Mockito.doReturn(authUserName).when(kvmStoragePoolMock).getAuthUserName(); + Mockito.doReturn(authSecret).when(kvmStoragePoolMock).getAuthSecret(); + + String expected = "rbd:volume1:mon_host=ceph-monitor\\:8000:auth_supported=cephx:id=admin:key=supersecret:rbd_default_format=2:client_mount_timeout=30"; + String result = KVMPhysicalDisk.RBDStringBuilder(kvmStoragePoolMock, "volume1"); + + Assert.assertEquals(expected, result); } @Test public void testRBDStringBuilder2() { String monHosts = "ceph-monitor1,ceph-monitor2,ceph-monitor3"; int monPort = 3300; + + Mockito.doReturn(monHosts).when(kvmStoragePoolMock).getSourceHost(); + Mockito.doReturn(monPort).when(kvmStoragePoolMock).getSourcePort(); + Mockito.doReturn(authUserName).when(kvmStoragePoolMock).getAuthUserName(); + Mockito.doReturn(authSecret).when(kvmStoragePoolMock).getAuthSecret(); + String expected = "rbd:volume1:" + "mon_host=ceph-monitor1\\:3300\\;ceph-monitor2\\:3300\\;ceph-monitor3\\:3300:" + "auth_supported=cephx:id=admin:key=supersecret:rbd_default_format=2:client_mount_timeout=30"; - String actualResult = KVMPhysicalDisk.RBDStringBuilder(monHosts, monPort, "admin", "supersecret", "volume1"); - assertEquals(expected, actualResult); + String actualResult = KVMPhysicalDisk.RBDStringBuilder(kvmStoragePoolMock, "volume1"); + + Assert.assertEquals(expected, actualResult); } @Test public void testRBDStringBuilder3() { String monHosts = "[fc00:1234::1],[fc00:1234::2],[fc00:1234::3]"; int monPort = 3300; + + Mockito.doReturn(monHosts).when(kvmStoragePoolMock).getSourceHost(); + Mockito.doReturn(monPort).when(kvmStoragePoolMock).getSourcePort(); + Mockito.doReturn(authUserName).when(kvmStoragePoolMock).getAuthUserName(); + Mockito.doReturn(authSecret).when(kvmStoragePoolMock).getAuthSecret(); + String expected = "rbd:volume1:" + "mon_host=[fc00\\:1234\\:\\:1]\\:3300\\;[fc00\\:1234\\:\\:2]\\:3300\\;[fc00\\:1234\\:\\:3]\\:3300:" + "auth_supported=cephx:id=admin:key=supersecret:rbd_default_format=2:client_mount_timeout=30"; - String actualResult = KVMPhysicalDisk.RBDStringBuilder(monHosts, monPort, "admin", "supersecret", "volume1"); - assertEquals(expected, actualResult); + String actualResult = KVMPhysicalDisk.RBDStringBuilder(kvmStoragePoolMock, "volume1"); + + Assert.assertEquals(expected, actualResult); } @Test @@ -64,18 +94,18 @@ public class KVMPhysicalDiskTest extends TestCase { LibvirtStoragePool pool = Mockito.mock(LibvirtStoragePool.class); KVMPhysicalDisk disk = new KVMPhysicalDisk(path, name, pool); - assertEquals(disk.getName(), name); - assertEquals(disk.getPath(), path); - assertEquals(disk.getPool(), pool); - assertEquals(disk.getSize(), 0); - assertEquals(disk.getVirtualSize(), 0); + Assert.assertEquals(disk.getName(), name); + Assert.assertEquals(disk.getPath(), path); + Assert.assertEquals(disk.getPool(), pool); + Assert.assertEquals(disk.getSize(), 0); + Assert.assertEquals(disk.getVirtualSize(), 0); disk.setSize(1024); disk.setVirtualSize(2048); - assertEquals(disk.getSize(), 1024); - assertEquals(disk.getVirtualSize(), 2048); + Assert.assertEquals(disk.getSize(), 1024); + Assert.assertEquals(disk.getVirtualSize(), 2048); disk.setFormat(PhysicalDiskFormat.RAW); - assertEquals(disk.getFormat(), PhysicalDiskFormat.RAW); + Assert.assertEquals(disk.getFormat(), PhysicalDiskFormat.RAW); } } diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index 79d3c4d04ff..c7e56f3421b 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -51,10 +51,6 @@ import java.util.concurrent.TimeoutException; import javax.naming.ConfigurationException; import javax.xml.parsers.ParserConfigurationException; -import com.trilead.ssh2.SFTPException; -import com.trilead.ssh2.SFTPv3Client; -import com.trilead.ssh2.SFTPv3DirectoryEntry; -import com.trilead.ssh2.SFTPv3FileAttributes; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.diagnostics.CopyToSecondaryStorageAnswer; import org.apache.cloudstack.diagnostics.CopyToSecondaryStorageCommand; @@ -66,12 +62,14 @@ import org.apache.cloudstack.storage.configdrive.ConfigDrive; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.cloudstack.utils.security.ParserUtils; + import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.maven.artifact.versioning.ComparableVersion; import org.apache.xmlrpc.XmlRpcException; + import org.joda.time.Duration; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -142,6 +140,7 @@ import com.cloud.utils.ExecutionResult; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.StringUtils; import com.cloud.utils.Ternary; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; @@ -152,6 +151,10 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VmDetailConstants; import com.trilead.ssh2.SCPClient; +import com.trilead.ssh2.SFTPException; +import com.trilead.ssh2.SFTPv3Client; +import com.trilead.ssh2.SFTPv3DirectoryEntry; +import com.trilead.ssh2.SFTPv3FileAttributes; import com.xensource.xenapi.Bond; import com.xensource.xenapi.Connection; import com.xensource.xenapi.Console; @@ -199,9 +202,9 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S */ RELVMOISCSI, NFS; - String _str; + final String _str; - private SRType() { + SRType() { _str = super.toString().toLowerCase(); } @@ -235,12 +238,11 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S protected static final HashMap s_powerStatesTable; public static final String XS_TOOLS_ISO_AFTER_70 = "guest-tools.iso"; - public static final String BASEPATH = "/opt/xensource/packages/resources/"; protected static final String PLATFORM_CORES_PER_SOCKET_KEY = "cores-per-socket"; static { - s_powerStatesTable = new HashMap(); + s_powerStatesTable = new HashMap<>(); s_powerStatesTable.put(VmPowerState.HALTED, PowerState.PowerOff); s_powerStatesTable.put(VmPowerState.PAUSED, PowerState.PowerOff); s_powerStatesTable.put(VmPowerState.RUNNING, PowerState.PowerOn); @@ -257,11 +259,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S // TODO : we need a better way to tell whether or not the VM belongs to // CloudStack final String vmName = vm.getNameLabel(conn); - if (vmName.matches("^[ivs]-\\d+-.+")) { - return false; - } - - return true; + return !vmName.matches("^[ivs]-\\d+-.+"); } protected IAgentControl _agentControl; @@ -282,7 +280,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final int _maxWeight = 256; protected int _migratewait; protected String _name; - protected Queue _password = new LinkedList(); + protected Queue _password = new LinkedList<>(); protected String _pod; protected int _pollingIntervalInSeconds = 60; @@ -296,7 +294,6 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S protected final int _sleep = 10000; protected String _storageNetworkName1; protected String _storageNetworkName2; - protected List _tmpDom0Vif = new ArrayList(); protected String _username; @@ -357,7 +354,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } public String callHostPlugin(final Connection conn, final String plugin, final String cmd, final String... params) { - final Map args = new HashMap(); + final Map args = new HashMap<>(); String msg; try { for (int i = 0; i < params.length; i += 2) { @@ -374,7 +371,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } return result.replace("\n", ""); } catch (final XenAPIException e) { - msg = "callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e.toString(); + msg = "callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e; logger.warn(msg); } catch (final XmlRpcException e) { msg = "callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e.getMessage(); @@ -385,12 +382,10 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S protected String callHostPluginAsync(final Connection conn, final String plugin, final String cmd, final int wait, final Map params) { final int timeout = wait * 1000; - final Map args = new HashMap(); + final Map args = new HashMap<>(); Task task = null; try { - for (final Map.Entry entry : params.entrySet()) { - args.put(entry.getKey(), entry.getValue()); - } + args.putAll(params); if (logger.isTraceEnabled()) { logger.trace("callHostPlugin executing for command " + cmd + " with " + getArgsString(args)); } @@ -407,13 +402,13 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } catch (final Types.HandleInvalid e) { logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to HandleInvalid clazz:" + e.clazz + ", handle:" + e.handle); } catch (final Exception e) { - logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e.toString(), e); + logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e, e); } finally { if (task != null) { try { task.destroy(conn); } catch (final Exception e1) { - logger.debug("unable to destroy task(" + task.toString() + ") on host(" + _host.getUuid() + ") due to " + e1.toString()); + logger.debug("unable to destroy task(" + task + ") on host(" + _host.getUuid() + ") due to " + e1); } } } @@ -422,7 +417,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S protected String callHostPluginAsync(final Connection conn, final String plugin, final String cmd, final int wait, final String... params) { final int timeout = wait * 1000; - final Map args = new HashMap(); + final Map args = new HashMap<>(); Task task = null; try { for (int i = 0; i < params.length; i += 2) { @@ -444,7 +439,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } catch (final Types.HandleInvalid e) { logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to HandleInvalid clazz:" + e.clazz + ", handle:" + e.handle); } catch (final XenAPIException e) { - logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e.toString(), e); + logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e, e); } catch (final Exception e) { logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e.getMessage(), e); } finally { @@ -452,7 +447,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { task.destroy(conn); } catch (final Exception e1) { - logger.debug("unable to destroy task(" + task.toString() + ") on host(" + _host.getUuid() + ") due to " + e1.toString()); + logger.debug("unable to destroy task(" + task + ") on host(" + _host.getUuid() + ") due to " + e1); } } } @@ -464,7 +459,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } protected String callHostPluginThroughMaster(final Connection conn, final String plugin, final String cmd, final String... params) { - final Map args = new HashMap(); + final Map args = new HashMap<>(); try { final Map poolRecs = Pool.getAllRecords(conn); @@ -487,7 +482,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } catch (final Types.HandleInvalid e) { logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to HandleInvalid clazz:" + e.clazz + ", handle:" + e.handle); } catch (final XenAPIException e) { - logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e.toString(), e); + logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e, e); } catch (final XmlRpcException e) { logger.warn("callHostPlugin failed for cmd: " + cmd + " with args " + getArgsString(args) + " due to " + e.getMessage(), e); } @@ -499,7 +494,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } public boolean canBridgeFirewall(final Connection conn) { - return Boolean.valueOf(callHostPlugin(conn, "vmops", "can_bridge_firewall", "host_uuid", _host.getUuid(), "instance", _instance)); + return Boolean.parseBoolean(callHostPlugin(conn, "vmops", "can_bridge_firewall", "host_uuid", _host.getUuid(), "instance", _instance)); } public void checkForSuccess(final Connection c, final Task task) throws XenAPIException, XmlRpcException { @@ -507,7 +502,6 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (logger.isTraceEnabled()) { logger.trace("Task " + task.getNameLabel(c) + " (" + task.getUuid(c) + ") completed"); } - return; } else { final String msg = "Task failed! Task record: " + task.getRecord(c); logger.warn(msg); @@ -521,7 +515,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { final SR.Record srr = sr.getRecord(conn); final Set pbds = sr.getPBDs(conn); - if (pbds.size() == 0) { + if (pbds.isEmpty()) { final String msg = "There is no PBDs for this SR: " + srr.nameLabel + " on host:" + _host.getUuid(); logger.warn(msg); return false; @@ -567,7 +561,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } } catch (final Exception e) { - final String msg = "checkSR failed host:" + _host + " due to " + e.toString(); + final String msg = "checkSR failed host:" + _host + " due to " + e; logger.warn(msg, e); return false; } @@ -580,7 +574,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S throw new ConfigurationException("Can not create connection to " + _host.getIp()); } try { - Host.Record hostRec = null; + Host.Record hostRec; try { final Host host = Host.getByUuid(conn, _host.getUuid()); hostRec = host.getRecord(conn); @@ -598,7 +592,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } finally { try { Session.logout(conn); - } catch (final Exception e) { + } catch (final Exception ignored) { } } } @@ -625,7 +619,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (VmPowerState.HALTED.equals(vmRec.powerState) && vmRec.affinity.equals(host) && !isAlienVm(vm, conn)) { try { - vm.destroy(conn); + destroyVm(vm, conn); } catch (final Exception e) { logger.warn("Catch Exception " + e.getClass().getName() + ": unable to destroy VM " + vmRec.nameLabel + " due to ", e); success = false; @@ -709,19 +703,19 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } public void cleanupTemplateSR(final Connection conn) { - Set pbds = null; + Set pbds; try { final Host host = Host.getByUuid(conn, _host.getUuid()); pbds = host.getPBDs(conn); } catch (final XenAPIException e) { - logger.warn("Unable to get the SRs " + e.toString(), e); - throw new CloudRuntimeException("Unable to get SRs " + e.toString(), e); + logger.warn("Unable to get the SRs " + e, e); + throw new CloudRuntimeException("Unable to get SRs " + e, e); } catch (final Exception e) { throw new CloudRuntimeException("Unable to get SRs " + e.getMessage(), e); } for (final PBD pbd : pbds) { - SR sr = null; - SR.Record srRec = null; + SR sr; + SR.Record srRec; try { sr = pbd.getSR(conn); srRec = sr.getRecord(conn); @@ -779,21 +773,20 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S // poll every 1 seconds , timeout after 2 hours waitForTask(conn, task, 1000, (long)wait * 1000); checkForSuccess(conn, task); - final VDI dvdi = Types.toVDI(task, conn); - return dvdi; + return Types.toVDI(task, conn); } finally { if (task != null) { try { task.destroy(conn); } catch (final Exception e) { - logger.debug("unable to destroy task(" + task.toString() + ") on host(" + _host.getUuid() + ") due to " + e.toString()); + logger.debug("unable to destroy task(" + task + ") on host(" + _host.getUuid() + ") due to " + e); } } } } public HashMap clusterVMMetaDataSync(final Connection conn) { - final HashMap vmMetaDatum = new HashMap(); + final HashMap vmMetaDatum = new HashMap<>(); try { final Map vm_map = VM.getAllRecords(conn); // USE if (vm_map != null) { @@ -809,7 +802,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } } } catch (final Throwable e) { - final String msg = "Unable to get vms through host " + _host.getUuid() + " due to " + e.toString(); + final String msg = "Unable to get vms through host " + _host.getUuid() + " due to " + e; logger.warn(msg, e); throw new CloudRuntimeException(msg); } @@ -933,13 +926,13 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S for (int i = 0; i <= _retry; i++) { try { final Set vms = VM.getByNameLabel(conn, vmName); - if (vms.size() < 1) { + if (vms.isEmpty()) { final String msg = "VM " + vmName + " is not running"; logger.warn(msg); return msg; } } catch (final Exception e) { - final String msg = "VM.getByNameLabel " + vmName + " failed due to " + e.toString(); + final String msg = "VM.getByNameLabel " + vmName + " failed due to " + e; logger.warn(msg, e); return msg; } @@ -951,7 +944,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } try { Thread.sleep(sleep); - } catch (final InterruptedException e) { + } catch (final InterruptedException ignored) { } } final String msg = "Timeout, Unable to logon to " + ipAddress; @@ -961,9 +954,9 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } public String copyVhdFromSecondaryStorage(final Connection conn, final String mountpoint, final String sruuid, final int wait) { - final String nameLabel = "cloud-" + UUID.randomUUID().toString(); + final String nameLabel = "cloud-" + UUID.randomUUID(); final String results = callHostPluginAsync(conn, "vmopspremium", "copy_vhd_from_secondarystorage", wait, "mountpoint", mountpoint, "sruuid", sruuid, "namelabel", nameLabel); - String errMsg = null; + String errMsg; if (results == null || results.isEmpty()) { errMsg = "copy_vhd_from_secondarystorage return null"; } else { @@ -992,7 +985,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { SshHelper.scpTo(_host.getIp(), 22, _username, null, _password.peek(), hostPath, content.getBytes(Charset.defaultCharset()), filename, null); } catch (final Exception e) { - logger.warn("scp VR config file into host " + _host.getIp() + " failed with exception " + e.getMessage().toString()); + logger.warn("scp VR config file into host " + _host.getIp() + " failed with exception " + e.getMessage()); } final String rc = callHostPlugin(conn, "vmops", "createFileInDomr", "domrip", routerIp, "srcfilepath", hostPath + filename, "dstfilepath", path, "cleanup", "true"); @@ -1020,20 +1013,20 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S protected SR createIsoSRbyURI(final Connection conn, final URI uri, final String vmName, final boolean shared) { try { - final Map deviceConfig = new HashMap(); + final Map deviceConfig = new HashMap<>(); final boolean isConfigDrive = uri.toString().endsWith(ConfigDrive.CONFIGDRIVEDIR); String path = uri.getPath(); path = path.replace("//", "/"); deviceConfig.put("location", uri.getHost() + ":" + path); final Host host = Host.getByUuid(conn, _host.getUuid()); - final SR sr = SR.create(conn, host, deviceConfig, new Long(0), uri.getHost() + path, "iso", "iso", "iso", shared, new HashMap()); + final SR sr = SR.create(conn, host, deviceConfig, 0L, uri.getHost() + path, "iso", "iso", "iso", shared, new HashMap<>()); sr.setNameLabel(conn, vmName + (isConfigDrive ? VM_NAME_CONFIGDRIVE_ISO_SUFFIX: VM_NAME_ISO_SUFFIX)); sr.setNameDescription(conn, deviceConfig.get("location")); sr.scan(conn); return sr; } catch (final XenAPIException e) { - final String msg = "createIsoSRbyURI failed! mountpoint: " + uri.getHost() + uri.getPath() + " due to " + e.toString(); + final String msg = "createIsoSRbyURI failed! mountpoint: " + uri.getHost() + uri.getPath() + " due to " + e; logger.warn(msg, e); throw new CloudRuntimeException(msg, e); } catch (final Exception e) { @@ -1049,12 +1042,12 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.debug("Creating a " + (shared ? "shared SR for " : "not shared SR for ") + uri); } - final Map deviceConfig = new HashMap(); + final Map deviceConfig = new HashMap<>(); String path = uri.getPath(); path = path.replace("//", "/"); deviceConfig.put("server", uri.getHost()); deviceConfig.put("serverpath", path); - final String name = UUID.nameUUIDFromBytes(new String(uri.getHost() + path).getBytes()).toString(); + final String name = UUID.nameUUIDFromBytes((uri.getHost() + path).getBytes()).toString(); if (!shared) { final Set srs = SR.getByNameLabel(conn, name); for (final SR sr : srs) { @@ -1066,9 +1059,9 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } final Host host = Host.getByUuid(conn, _host.getUuid()); - final Map smConfig = new HashMap(); + final Map smConfig = new HashMap<>(); smConfig.put("nosubdir", "true"); - final SR sr = SR.create(conn, host, deviceConfig, new Long(0), name, uri.getHost() + uri.getPath(), SRType.NFS.toString(), "user", shared, smConfig); + final SR sr = SR.create(conn, host, deviceConfig, 0L, name, uri.getHost() + uri.getPath(), SRType.NFS.toString(), "user", shared, smConfig); if (!checkSR(conn, sr)) { throw new Exception("no attached PBD"); @@ -1079,7 +1072,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S sr.scan(conn); return sr; } catch (final XenAPIException e) { - final String msg = "Can not create second storage SR mountpoint: " + uri.getHost() + uri.getPath() + " due to " + e.toString(); + final String msg = "Can not create second storage SR mountpoint: " + uri.getHost() + uri.getPath() + " due to " + e; logger.warn(msg, e); throw new CloudRuntimeException(msg, e); } catch (final Exception e) { @@ -1153,7 +1146,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final String tmpltLocalDir = UUID.randomUUID().toString(); final String results = callHostPluginAsync(conn, "vmopspremium", "create_privatetemplate_from_snapshot", wait, "templatePath", templatePath, "snapshotPath", snapshotPath, "tmpltLocalDir", tmpltLocalDir); - String errMsg = null; + String errMsg; if (results == null || results.isEmpty()) { errMsg = "create_privatetemplate_from_snapshot return null"; } else { @@ -1211,7 +1204,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } else { vbdr.mode = Types.VbdMode.RW; vbdr.type = Types.VbdType.DISK; - vbdr.unpluggable = (volume.getType() == Volume.Type.ROOT) ? false : true; + vbdr.unpluggable = volume.getType() != Volume.Type.ROOT; vbdr.userdevice = "autodetect"; final Long deviceId = volume.getDiskSeq(); if (deviceId != null && (!isDeviceUsed(conn, vm, deviceId) || deviceId > 3)) { @@ -1264,7 +1257,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S vifr.MAC = nic.getMac(); // Nicira needs these IDs to find the NIC - vifr.otherConfig = new HashMap(); + vifr.otherConfig = new HashMap<>(); vifr.otherConfig.put("nicira-iface-id", nic.getUuid()); vifr.otherConfig.put("nicira-vm-id", vm.getUuid(conn)); // Provide XAPI with the cloudstack vm and nic uids. @@ -1279,9 +1272,9 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S vifr.otherConfig.put("cloudstack-network-id", nic.getNetworkUuid()); vifr.network = getNetwork(conn, nic); - if (nic.getNetworkRateMbps() != null && nic.getNetworkRateMbps().intValue() != -1) { + if (nic.getNetworkRateMbps() != null && nic.getNetworkRateMbps() != -1) { vifr.qosAlgorithmType = "ratelimit"; - vifr.qosAlgorithmParams = new HashMap(); + vifr.qosAlgorithmParams = new HashMap<>(); // convert mbs to kilobyte per second vifr.qosAlgorithmParams.put("kbps", Integer.toString(nic.getNetworkRateMbps() * 128)); } @@ -1322,18 +1315,18 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S // be the minumum of // recommended value for that template and capacity remaining on host - long recommendedMemoryMin = 0l; - long recommendedMemoryMax = 0l; + long recommendedMemoryMin = 0L; + long recommendedMemoryMax = 0L; Map guestOsDetails = vmSpec.getGuestOsDetails(); if (guestOsDetails != null) { if (guestOsDetails.containsKey("xenserver.dynamicMin")) { - recommendedMemoryMin = Long.valueOf(guestOsDetails.get("xenserver.dynamicMin")).longValue(); + recommendedMemoryMin = Long.parseLong(guestOsDetails.get("xenserver.dynamicMin")); } if (guestOsDetails.containsKey("xenserver.dynamicMax")) { - recommendedMemoryMax = Long.valueOf(guestOsDetails.get("xenserver.dynamicMax")).longValue(); + recommendedMemoryMax = Long.parseLong(guestOsDetails.get("xenserver.dynamicMax")); } } @@ -1370,10 +1363,10 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (vmSpec.getType() == VirtualMachine.Type.NetScalerVm) { NicTO mgmtNic = vmSpec.getNics()[0]; if (mgmtNic != null) { - Map xenstoreData = new HashMap(3); - xenstoreData.put(XENSTORE_DATA_IP, mgmtNic.getIp().toString().trim()); - xenstoreData.put(XENSTORE_DATA_GATEWAY, mgmtNic.getGateway().toString().trim()); - xenstoreData.put(XENSTORE_DATA_NETMASK, mgmtNic.getNetmask().toString().trim()); + Map xenstoreData = new HashMap<>(3); + xenstoreData.put(XENSTORE_DATA_IP, mgmtNic.getIp().trim()); + xenstoreData.put(XENSTORE_DATA_GATEWAY, mgmtNic.getGateway().trim()); + xenstoreData.put(XENSTORE_DATA_NETMASK, mgmtNic.getNetmask().trim()); vmr.xenstoreData = xenstoreData; } } @@ -1381,11 +1374,11 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final VM vm = VM.create(conn, vmr); logger.debug("Created VM " + vm.getUuid(conn) + " for " + vmSpec.getName()); - final Map vcpuParams = new HashMap(); + final Map vcpuParams = new HashMap<>(); final Integer speed = vmSpec.getMinSpeed(); if (speed != null) { - int cpuWeight = _maxWeight; // cpu_weight + int cpuWeight; // cpu_weight int utilization = 0; // max CPU cap, default is unlimited // weight based allocation, CPU weight is calculated per VCPU @@ -1405,12 +1398,12 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } - if (vcpuParams.size() > 0) { + if (!vcpuParams.isEmpty()) { vm.setVCPUsParams(conn, vcpuParams); } final String bootArgs = vmSpec.getBootArgs(); - if (bootArgs != null && bootArgs.length() > 0) { + if (bootArgs != null && !bootArgs.isEmpty()) { // send boot args for PV instances String pvargs = vm.getPVArgs(conn); pvargs = pvargs + vmSpec.getBootArgs().replaceAll(" ", "%"); @@ -1450,7 +1443,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S vm.setPVBootloader(conn, "pygrub"); vm.setPVBootloaderArgs(conn, CitrixHelper.getPVbootloaderArgs(guestOsTypeName)); } else { - vm.destroy(conn); + destroyVm(vm, conn, true); throw new CloudRuntimeException("Unable to handle boot loader type: " + vmSpec.getBootloader()); } } @@ -1470,18 +1463,17 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } public VM createWorkingVM(final Connection conn, final String vmName, final String guestOSType, final String platformEmulator, final List listVolumeTo) - throws BadServerResponse, Types.VmBadPowerState, Types.SrFull, Types.OperationNotAllowed, XenAPIException, XmlRpcException { + throws XenAPIException, XmlRpcException { // below is redundant but keeping for consistency and code readabilty - final String guestOsTypeName = platformEmulator; - if (guestOsTypeName == null) { + if (platformEmulator == null) { final String msg = " Hypervisor " + this.getClass().getName() + " doesn't support guest OS type " + guestOSType + ". you can choose 'Other install media' to run it as HVM"; logger.warn(msg); throw new CloudRuntimeException(msg); } - final VM template = getVM(conn, guestOsTypeName); + final VM template = getVM(conn, platformEmulator); final VM vm = template.createClone(conn, vmName); vm.setIsATemplate(conn, false); - final Map vdiMap = new HashMap(); + final Map vdiMap = new HashMap<>(); for (final VolumeObjectTO volume : listVolumeTo) { final String vdiUuid = volume.getPath(); try { @@ -1524,10 +1516,9 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S protected String deleteSnapshotBackup(final Connection conn, final Long dcId, final Long accountId, final Long volumeId, final String secondaryStorageMountPath, final String backupUUID) { // If anybody modifies the formatting below again, I'll skin them - final String result = callHostPlugin(conn, "vmopsSnapshot", "deleteSnapshotBackup", "backupUUID", backupUUID, "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId", - volumeId.toString(), "secondaryStorageMountPath", secondaryStorageMountPath); - return result; + return callHostPlugin(conn, "vmopsSnapshot", "deleteSnapshotBackup", "backupUUID", backupUUID, "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId", + volumeId.toString(), "secondaryStorageMountPath", secondaryStorageMountPath); } public void destroyPatchVbd(final Connection conn, final Set vms) throws XmlRpcException, XenAPIException { @@ -1551,12 +1542,12 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S vbd.eject(conn); } } catch (Exception e) { - logger.debug("Cannot eject CD-ROM device for VM " + vmName + " due to " + e.toString(), e); + logger.debug("Cannot eject CD-ROM device for VM " + vmName + " due to " + e, e); } try { vbd.destroy(conn); } catch (Exception e) { - logger.debug("Cannot destroy CD-ROM device for VM " + vmName + " due to " + e.toString(), e); + logger.debug("Cannot destroy CD-ROM device for VM " + vmName + " due to " + e, e); } break; } @@ -1572,10 +1563,8 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (res.length != 2 || !res[0].equalsIgnoreCase("SUCCESS")) { throw new CloudRuntimeException("Unable to remove OVS bridge " + bridge + ":" + result); } - return; } catch (final Exception e) { logger.warn("destroyTunnelNetwork failed:", e); - return; } } @@ -1590,7 +1579,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { vdi.destroy(conn); } catch (final Exception e) { - final String msg = "Failed to destroy VDI : " + nameLabel + "due to " + e.toString() + "\n Force deleting VDI using system 'rm' command"; + final String msg = "Failed to destroy VDI : " + nameLabel + "due to " + e + "\n Force deleting VDI using system 'rm' command"; logger.warn(msg); try { final String srUUID = vdi.getSR(conn).getUuid(conn); @@ -1602,7 +1591,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } } } - } catch (final Exception e) { + } catch (final Exception ignored) { } } @@ -1627,7 +1616,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } return true; } catch (final Exception e) { - logger.warn("Catch exception " + e.toString(), e); + logger.warn("Catch exception " + e, e); return false; } finally { sshConnection.close(); @@ -1637,10 +1626,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S public boolean doPingTest(final Connection conn, final String domRIp, final String vmIp) { final String args = "-i " + domRIp + " -p " + vmIp; final String result = callHostPlugin(conn, "vmops", "pingtest", "args", args); - if (result == null || result.isEmpty()) { - return false; - } - return true; + return result != null && !result.isEmpty(); } /** @@ -1691,8 +1677,8 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S * @throws XmlRpcException */ protected Network enableVlanNetwork(final Connection conn, final long tag, final XsLocalNetwork network) throws XenAPIException, XmlRpcException { - Network vlanNetwork = null; - final String oldName = "VLAN" + Long.toString(tag); + Network vlanNetwork; + final String oldName = "VLAN" + tag; final String newName = "VLAN-" + network.getNetworkRecord(conn).uuid + "-" + tag; XsLocalNetwork vlanNic = getNetworkByName(conn, newName); if (vlanNic == null) { @@ -1711,7 +1697,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } final Network.Record nwr = new Network.Record(); nwr.nameLabel = newName; - nwr.tags = new HashSet(); + nwr.tags = new HashSet<>(); nwr.tags.add(generateTimeStamp()); vlanNetwork = Network.create(conn, nwr); vlanNic = getNetworkByName(conn, newName); @@ -1803,7 +1789,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S Map details = cmd.getHostDetails(); if (details == null) { - details = new HashMap(); + details = new HashMap<>(); } String productBrand = hr.softwareVersion.get("product_brand"); @@ -1828,7 +1814,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S cmd.setPool(_host.getPool()); cmd.setDataCenter(Long.toString(_dcId)); for (final String cap : hr.capabilities) { - if (cap.length() > 0) { + if (!cap.isEmpty()) { caps.append(cap).append(" , "); } } @@ -1843,7 +1829,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final HostMetrics hm = host.getMetrics(conn); - long ram = 0; + long ram; long dom0Ram = 0; ram = hm.getMemoryTotal(conn); final Set vms = host.getResidentVMs(conn); @@ -1864,7 +1850,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S PIF pif = PIF.getByUuid(conn, _host.getPrivatePif()); PIF.Record pifr = pif.getRecord(conn); - if (pifr.IP != null && pifr.IP.length() > 0) { + if (pifr.IP != null && !pifr.IP.isEmpty()) { cmd.setPrivateIpAddress(pifr.IP); cmd.setPrivateMacAddress(pifr.MAC); cmd.setPrivateNetmask(pifr.netmask); @@ -1876,7 +1862,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S pif = PIF.getByUuid(conn, _host.getPublicPif()); pifr = pif.getRecord(conn); - if (pifr.IP != null && pifr.IP.length() > 0) { + if (pifr.IP != null && !pifr.IP.isEmpty()) { cmd.setPublicIpAddress(pifr.IP); cmd.setPublicMacAddress(pifr.MAC); cmd.setPublicNetmask(pifr.netmask); @@ -1885,7 +1871,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (_host.getStoragePif1() != null) { pif = PIF.getByUuid(conn, _host.getStoragePif1()); pifr = pif.getRecord(conn); - if (pifr.IP != null && pifr.IP.length() > 0) { + if (pifr.IP != null && !pifr.IP.isEmpty()) { cmd.setStorageIpAddress(pifr.IP); cmd.setStorageMacAddress(pifr.MAC); cmd.setStorageNetmask(pifr.netmask); @@ -1895,7 +1881,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (_host.getStoragePif2() != null) { pif = PIF.getByUuid(conn, _host.getStoragePif2()); pifr = pif.getRecord(conn); - if (pifr.IP != null && pifr.IP.length() > 0) { + if (pifr.IP != null && !pifr.IP.isEmpty()) { cmd.setStorageIpAddressDeux(pifr.IP); cmd.setStorageMacAddressDeux(pifr.MAC); cmd.setStorageNetmaskDeux(pifr.netmask); @@ -1915,7 +1901,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S Pair result = xenServerUtilitiesHelper.executeSshWrapper(_host.getIp(), 22, _username, null, getPwdFromQueue(), cmdLine); - boolean supportsClonedVolumes = result != null && result.first() != null && result.first() && result.second() != null && result.second().length() > 0; + boolean supportsClonedVolumes = result != null && result.first() != null && result.first() && result.second() != null && !result.second().isEmpty(); cmd.setSupportsClonedVolumes(supportsClonedVolumes); } catch (NumberFormatException ex) { @@ -1924,9 +1910,9 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } catch (final XmlRpcException e) { throw new CloudRuntimeException("XML RPC Exception: " + e.getMessage(), e); } catch (final XenAPIException e) { - throw new CloudRuntimeException("XenAPIException: " + e.toString(), e); + throw new CloudRuntimeException("XenAPIException: " + e, e); } catch (final Exception e) { - throw new CloudRuntimeException("Exception: " + e.toString(), e); + throw new CloudRuntimeException("Exception: " + e, e); } } @@ -2001,16 +1987,16 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S */ public synchronized Network findOrCreateTunnelNetwork(final Connection conn, final String nwName) { try { - Network nw = null; + Network nw; final Network.Record rec = new Network.Record(); final Set networks = Network.getByNameLabel(conn, nwName); - if (networks.size() == 0) { + if (networks.isEmpty()) { rec.nameDescription = "tunnel network id# " + nwName; rec.nameLabel = nwName; // Initialize the ovs-host-setup to avoid error when doing // get-param in plugin - final Map otherConfig = new HashMap(); + final Map otherConfig = new HashMap<>(); otherConfig.put("ovs-host-setup", ""); // Mark 'internal network' as shared so bridge gets // automatically created on each host in the cluster @@ -2036,16 +2022,16 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final Long domId = vm.getDomid(conn); callHostPlugin(conn, "vmopspremium", "forceShutdownVM", "domId", domId.toString()); vm.powerStateReset(conn); - vm.destroy(conn); + destroyVm(vm, conn); } catch (final Exception e) { - final String msg = "forceShutdown failed due to " + e.toString(); + final String msg = "forceShutdown failed due to " + e; logger.warn(msg, e); throw new CloudRuntimeException(msg); } } protected String generateTimeStamp() { - return new StringBuilder("CsCreateTime-").append(System.currentTimeMillis()).append("-").append(Rand.nextInt(Integer.MAX_VALUE)).toString(); + return "CsCreateTime" + System.currentTimeMillis() + "-" + Rand.nextInt(Integer.MAX_VALUE); } @Override @@ -2056,7 +2042,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S protected String getArgsString(final Map args) { final StringBuilder argString = new StringBuilder(); for (final Map.Entry arg : args.entrySet()) { - argString.append(arg.getKey() + ": " + arg.getValue() + ", "); + argString.append(arg.getKey()).append(": ").append(arg.getValue()).append(", "); } return argString.toString(); } @@ -2072,11 +2058,11 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S protected Pair getControlDomain(final Connection conn) throws XenAPIException, XmlRpcException { final Host host = Host.getByUuid(conn, _host.getUuid()); - Set vms = null; + Set vms; vms = host.getResidentVMs(conn); for (final VM vm : vms) { if (vm.getIsControlDomain(conn)) { - return new Pair(vm, vm.getRecord(conn)); + return new Pair<>(vm, vm.getRecord(conn)); } } @@ -2223,9 +2209,11 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } // would hcs be null we would have thrown an exception on condition // (_host.getCpus() <= 0) by now - for (final HostCpu hc : hcs) { - _host.setSpeed(hc.getSpeed(conn).intValue()); - break; + if (hcs != null) { + for (final HostCpu hc : hcs) { + _host.setSpeed(hc.getSpeed(conn).intValue()); + break; + } } final Host.Record hr = myself.getRecord(conn); _host.setProductVersion(CitrixHelper.getProductVersion(hr)); @@ -2236,7 +2224,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S _host.setPrivateNetwork(privateNic.getNetworkRecord(conn).uuid); _host.setSystemvmisouuid(null); - XsLocalNetwork guestNic = null; + XsLocalNetwork guestNic; if (_guestNetworkName != null && !_guestNetworkName.equals(_privateNetworkName)) { guestNic = getNetworkByName(conn, _guestNetworkName); if (guestNic == null) { @@ -2250,7 +2238,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S _host.setGuestNetwork(guestNic.getNetworkRecord(conn).uuid); _host.setGuestPif(guestNic.getPifRecord(conn).uuid); - XsLocalNetwork publicNic = null; + XsLocalNetwork publicNic; if (_publicNetworkName != null && !_publicNetworkName.equals(_guestNetworkName)) { publicNic = getNetworkByName(conn, _publicNetworkName); if (publicNic == null) { @@ -2266,7 +2254,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (_storageNetworkName1 == null) { _storageNetworkName1 = _guestNetworkName; } - XsLocalNetwork storageNic1 = null; + XsLocalNetwork storageNic1; storageNic1 = getNetworkByName(conn, _storageNetworkName1); if (storageNic1 == null) { logger.warn("Unable to find storage network " + _storageNetworkName1 + " for host " + _host.getIp()); @@ -2276,7 +2264,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S _host.setStoragePif1(storageNic1.getPifRecord(conn).uuid); } - XsLocalNetwork storageNic2 = null; + XsLocalNetwork storageNic2; if (_storageNetworkName2 != null) { storageNic2 = getNetworkByName(conn, _storageNetworkName2); if (storageNic2 != null) { @@ -2290,9 +2278,6 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.info("Public Network is " + _publicNetworkName + " for host " + _host.getIp()); return true; - } catch (final XenAPIException e) { - logger.warn("Unable to get host information for " + _host.getIp(), e); - return false; } catch (final Exception e) { logger.warn("Unable to get host information for " + _host.getIp(), e); return false; @@ -2371,7 +2356,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } protected HashMap getHostVmStateReport(final Connection conn) { - final HashMap vmStates = new HashMap(); + final HashMap vmStates = new HashMap<>(); Map vm_map = null; for (int i = 0; i < 2; i++) { try { @@ -2382,7 +2367,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } try { Thread.sleep(1000); - } catch (final InterruptedException ex) { + } catch (final InterruptedException ignored) { } } @@ -2397,20 +2382,15 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final VmPowerState ps = record.powerState; final Host host = record.residentOn; - String host_uuid = null; + String host_uuid; if (!isRefNull(host)) { try { host_uuid = host.getUuid(conn); - } catch (final BadServerResponse e) { + if (host_uuid.equalsIgnoreCase(_host.getUuid())) { + vmStates.put(record.nameLabel, new HostVmStateReportEntry(convertToPowerState(ps), host_uuid)); + } + } catch (final XmlRpcException | XenAPIException e) { logger.error("Failed to get host uuid for host " + host.toWireString(), e); - } catch (final XenAPIException e) { - logger.error("Failed to get host uuid for host " + host.toWireString(), e); - } catch (final XmlRpcException e) { - logger.error("Failed to get host uuid for host " + host.toWireString(), e); - } - - if (host_uuid.equalsIgnoreCase(_host.getUuid())) { - vmStates.put(record.nameLabel, new HostVmStateReportEntry(convertToPowerState(ps), host_uuid)); } } } @@ -2433,13 +2413,13 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S public SR getIscsiSR(final Connection conn, final String srNameLabel, final String target, String path, final String chapInitiatorUsername, final String chapInitiatorPassword, final boolean resignature, final String srType, final boolean ignoreIntroduceException) { synchronized (srNameLabel.intern()) { - final Map deviceConfig = new HashMap(); + final Map deviceConfig = new HashMap<>(); try { if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } - final String tmp[] = path.split("/"); + final String[] tmp = path.split("/"); if (tmp.length != 3) { final String msg = "Wrong iscsi path " + path + " it should be /targetIQN/LUN"; logger.warn(msg); @@ -2447,7 +2427,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } final String targetiqn = tmp[1].trim(); final String lunid = tmp[2].trim(); - String scsiid = ""; + String scsiid; //Throws an exception if SR already exists and is attached checkIfIscsiSrExisits(conn, srNameLabel, target, targetiqn, lunid); @@ -2465,8 +2445,8 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } final Host host = Host.getByUuid(conn, _host.getUuid()); - final Map smConfig = new HashMap(); - SR sr = null; + final Map smConfig = new HashMap<>(); + SR sr; String pooluuid = null; if (SRType.LVMOISCSI.equals(srType)) { @@ -2474,13 +2454,13 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S deviceConfig.put("SCSIid", scsiid); String result = SR.probe(conn, host, deviceConfig, srType, smConfig); - if (result.indexOf("") != -1) { + if (result.contains("")) { pooluuid = result.substring(result.indexOf("") + 6, result.indexOf("")).trim(); } } if (pooluuid == null || pooluuid.length() != 36) { - sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, srType, "user", true, smConfig); + sr = SR.create(conn, host, deviceConfig, 0L, srNameLabel, srNameLabel, srType, "user", true, smConfig); } else { if (resignature) { // We resignature the SR for managed storage if needed. At the end of this @@ -2495,7 +2475,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S return sr; } catch (final XenAPIException e) { - final String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.toString(); + final String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e; logger.warn(msg, e); throw new CloudRuntimeException(msg, e); } catch (final Exception e) { @@ -2548,7 +2528,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S String pooluuid; try { - SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, SRType.RELVMOISCSI.toString(), "user", true, smConfig); + SR.create(conn, host, deviceConfig, 0L, srNameLabel, srNameLabel, SRType.RELVMOISCSI.toString(), "user", true, smConfig); // The successful outcome of SR.create (right above) is to throw an exception of type XenAPIException (with expected // toString() text) after resigning the metadata (we indicated to perform a resign by passing in SRType.RELVMOISCSI.toString()). @@ -2567,7 +2547,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S pooluuid = null; - if (result.indexOf("") != -1) { + if (result.contains("")) { pooluuid = result.substring(result.indexOf("") + 6, result.indexOf("")).trim(); } @@ -2616,11 +2596,11 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S String scsiid = null; try { - SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true, smConfig); + SR.create(conn, host, deviceConfig, 0L, srNameLabel, srNameLabel, type, "user", true, smConfig); } catch (final XenAPIException e) { final String errmsg = e.toString(); if (errmsg.contains("SR_BACKEND_FAILURE_107")) { - final String lun[] = errmsg.split(""); + final String[] lun = errmsg.split(""); boolean found = false; for (int i = 1; i < lun.length; i++) { final int blunindex = lun[i].indexOf("") + 7; @@ -2642,7 +2622,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S throw new CloudRuntimeException(msg); } } else { - final String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.toString(); + final String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e; logger.warn(msg, e); throw new CloudRuntimeException(msg, e); } @@ -2654,7 +2634,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { final Set srs = SR.getByNameLabel(conn, vmName + (isConfigDrive ? VM_NAME_CONFIGDRIVE_ISO_SUFFIX : VM_NAME_ISO_SUFFIX)); - if (srs.size() == 0) { + if (srs.isEmpty()) { return null; } else if (srs.size() == 1) { return srs.iterator().next(); @@ -2663,7 +2643,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.warn(msg); } } catch (final XenAPIException e) { - final String msg = "getIsoSRbyVmName failed due to " + e.toString(); + final String msg = "getIsoSRbyVmName failed due to " + e; logger.warn(msg, e); } catch (final Exception e) { final String msg = "getIsoSRbyVmName failed due to " + e.getMessage(); @@ -2673,8 +2653,8 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } public VDI getIsoVDIByURL(final Connection conn, final String vmName, final String isoURL) { - SR isoSR = null; - String mountpoint = null; + SR isoSR; + String mountpoint; if (isoURL.startsWith("xs-tools")) { try { final String actualIsoURL = getActualIsoTemplate(conn); @@ -2684,10 +2664,8 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } return vdis.iterator().next(); - } catch (final XenAPIException e) { - throw new CloudRuntimeException("Unable to get pv iso: " + isoURL + " due to " + e.toString()); } catch (final Exception e) { - throw new CloudRuntimeException("Unable to get pv iso: " + isoURL + " due to " + e.toString()); + throw new CloudRuntimeException("Unable to get pv iso: " + isoURL + " due to " + e); } } @@ -2751,15 +2729,14 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S public String getLabel() { final Connection conn = getConnection(); - final String result = callHostPlugin(conn, "ovstunnel", "getLabel"); - return result; + return callHostPlugin(conn, "ovstunnel", "getLabel"); } public String getLowestAvailableVIFDeviceNum(final Connection conn, final VM vm) { String vmName = ""; try { vmName = vm.getNameLabel(conn); - final List usedDeviceNums = new ArrayList(); + final List usedDeviceNums = new ArrayList<>(); final Set vifs = vm.getVIFs(conn); final Iterator vifIter = vifs.iterator(); while (vifIter.hasNext()) { @@ -2789,7 +2766,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final String msg = "Caught XmlRpcException: " + e.getMessage(); logger.warn(msg, e); } catch (final XenAPIException e) { - final String msg = "Caught XenAPIException: " + e.toString(); + final String msg = "Caught XenAPIException: " + e; logger.warn(msg, e); } @@ -2805,8 +2782,8 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final PIF.Record rec = pif.getRecord(conn); if (rec.management) { if (rec.VLAN != null && rec.VLAN != -1) { - final String msg = new StringBuilder("Unsupported configuration. Management network is on a VLAN. host=").append(_host.getUuid()).append("; pif=").append(rec.uuid) - .append("; vlan=").append(rec.VLAN).toString(); + final String msg = "Unsupported configuration. Management network is on a VLAN. host=" + _host.getUuid() + "; pif=" + rec.uuid + + "; vlan=" + rec.VLAN; logger.warn(msg); throw new CloudRuntimeException(msg); } @@ -2872,7 +2849,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final String name = nic.getName(); final XsLocalNetwork network = getNativeNetworkForTraffic(conn, nic.getType(), name); if (network == null) { - logger.error("Network is not configured on the backend for nic " + nic.toString()); + logger.error("Network is not configured on the backend for nic " + nic); throw new CloudRuntimeException("Network for the backend is not configured correctly for network broadcast domain: " + nic.getBroadcastUri()); } final URI uri = nic.getBroadcastUri(); @@ -2959,7 +2936,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S return new XsLocalNetwork(this, networks.iterator().next(), null, null, null); } - if (networks.size() == 0) { + if (networks.isEmpty()) { return null; } @@ -3044,7 +3021,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } public SR getNfsSR(final Connection conn, final String poolid, final String uuid, final String server, String serverpath, final String pooldesc) { - final Map deviceConfig = new HashMap(); + final Map deviceConfig = new HashMap<>(); try { serverpath = serverpath.replace("//", "/"); final Set srs = SR.getAll(conn); @@ -3085,14 +3062,12 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S deviceConfig.put("server", server); deviceConfig.put("serverpath", serverpath); final Host host = Host.getByUuid(conn, _host.getUuid()); - final Map smConfig = new HashMap(); + final Map smConfig = new HashMap<>(); smConfig.put("nosubdir", "true"); - final SR sr = SR.create(conn, host, deviceConfig, new Long(0), uuid, poolid, SRType.NFS.toString(), "user", true, smConfig); + final SR sr = SR.create(conn, host, deviceConfig, 0L, uuid, poolid, SRType.NFS.toString(), "user", true, smConfig); sr.scan(conn); return sr; - } catch (final XenAPIException e) { - throw new CloudRuntimeException("Unable to create NFS SR " + pooldesc, e); - } catch (final XmlRpcException e) { + } catch (final XenAPIException | XmlRpcException e) { throw new CloudRuntimeException("Unable to create NFS SR " + pooldesc, e); } } @@ -3116,7 +3091,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (patchfilePath == null) { throw new CloudRuntimeException("Unable to find patch file " + patch); } - List files = new ArrayList(); + List files = new ArrayList<>(); files.add(new File(patchfilePath)); return files; } @@ -3124,7 +3099,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S protected abstract String getPatchFilePath(); public String getPerfMon(final Connection conn, final Map params, final int wait) { - String result = null; + String result; try { result = callHostPluginAsync(conn, "vmopspremium", "asmonitor", 60, params); if (result != null) { @@ -3142,10 +3117,10 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S * Note: 1 => called from host, hence host stats 2 => called from vm, * hence vm stats */ - Document doc = null; + Document doc; try { - doc = getStatsRawXML(conn, flag == 1 ? true : false); + doc = getStatsRawXML(conn, flag == 1); } catch (final Exception e1) { logger.warn("Error whilst collecting raw stats from plugin: ", e1); return null; @@ -3167,12 +3142,16 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final NodeList metaNodeChildren = metaNode.getChildNodes(); for (int i = 0; i < metaNodeChildren.getLength(); i++) { final Node n = metaNodeChildren.item(i); - if (n.getNodeName().equals("rows")) { - numRows = Integer.valueOf(getXMLNodeValue(n)); - } else if (n.getNodeName().equals("columns")) { - numColumns = Integer.valueOf(getXMLNodeValue(n)); - } else if (n.getNodeName().equals("legend")) { - legend = n; + switch (n.getNodeName()) { + case "rows": + numRows = Integer.valueOf(getXMLNodeValue(n)); + break; + case "columns": + numColumns = Integer.valueOf(getXMLNodeValue(n)); + break; + case "legend": + legend = n; + break; } } @@ -3184,7 +3163,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S return 0; } - protected SR getSRByNameLabelandHost(final Connection conn, final String name) throws BadServerResponse, XenAPIException, XmlRpcException { + protected SR getSRByNameLabelandHost(final Connection conn, final String name) throws XenAPIException, XmlRpcException { final Set srs = SR.getByNameLabel(conn, name); SR ressr = null; for (final SR sr : srs) { @@ -3255,13 +3234,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } catch (final MalformedURLException e) { logger.warn("Malformed URL? come on...." + urlStr); return null; - } catch (final IOException e) { - logger.warn("Problems getting stats using " + urlStr, e); - return null; - } catch (final SAXException e) { - logger.warn("Problems getting stats using " + urlStr, e); - return null; - } catch (final ParserConfigurationException e) { + } catch (final IOException | ParserConfigurationException | SAXException e) { logger.warn("Problems getting stats using " + urlStr, e); return null; } finally { @@ -3280,7 +3253,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { srs = SR.getByNameLabel(conn, srNameLabel); } catch (final XenAPIException e) { - throw new CloudRuntimeException("Unable to get SR " + srNameLabel + " due to " + e.toString(), e); + throw new CloudRuntimeException("Unable to get SR " + srNameLabel + " due to " + e, e); } catch (final Exception e) { throw new CloudRuntimeException("Unable to get SR " + srNameLabel + " due to " + e.getMessage(), e); } @@ -3324,7 +3297,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.warn(msg); return null; } catch (final XenAPIException e) { - final String msg = "getVDIbyLocationandSR exception " + loc + " due to " + e.toString(); + final String msg = "getVDIbyLocationandSR exception " + loc + " due to " + e; logger.warn(msg, e); throw new CloudRuntimeException(msg, e); } catch (final Exception e) { @@ -3344,7 +3317,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S return VDI.getByUuid(conn, uuid); } catch (final Exception e) { if (throwExceptionIfNotFound) { - final String msg = "Catch Exception " + e.getClass().getName() + " :VDI getByUuid for uuid: " + uuid + " failed due to " + e.toString(); + final String msg = "Catch Exception " + e.getClass().getName() + " :VDI getByUuid for uuid: " + uuid + " failed due to " + e; logger.debug(msg); @@ -3388,13 +3361,13 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { vms = VM.getByNameLabel(conn, vmName); } catch (final XenAPIException e) { - throw new CloudRuntimeException("Unable to get " + vmName + ": " + e.toString(), e); + throw new CloudRuntimeException("Unable to get " + vmName + ": " + e, e); } catch (final Exception e) { throw new CloudRuntimeException("Unable to get " + vmName + ": " + e.getMessage(), e); } // If there are no VMs, throw an exception - if (vms.size() == 0) { + if (vms.isEmpty()) { throw new CloudRuntimeException("VM with name: " + vmName + " does not exist."); } @@ -3412,7 +3385,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } public long getVMSnapshotChainSize(final Connection conn, final VolumeObjectTO volumeTo, final String vmName, final String vmSnapshotName) - throws BadServerResponse, XenAPIException, XmlRpcException { + throws XenAPIException, XmlRpcException { if (volumeTo.getVolumeType() == Volume.Type.DATADISK) { final VDI dataDisk = VDI.getByUuid(conn, volumeTo.getPath()); if (dataDisk != null) { @@ -3434,12 +3407,11 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S size = size + vdi.getPhysicalUtilisation(conn); // add size of snapshot vdi parent, this contains data if (!isRefNull(parentVDI)) { - size = size + parentVDI.getPhysicalUtilisation(conn).longValue(); + size = size + parentVDI.getPhysicalUtilisation(conn); } } } catch (final Exception e) { - logger.debug("Exception occurs when calculate snapshot capacity for volumes: due to " + e.toString()); - continue; + logger.debug("Exception occurs when calculate snapshot capacity for volumes: due to " + e); } } if (volumeTo.getVolumeType() == Volume.Type.ROOT) { @@ -3466,8 +3438,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } } } catch (Exception e) { - logger.debug("Exception occurs when calculate snapshot capacity for memory: due to " + e.toString()); - continue; + logger.debug("Exception occurs when calculate snapshot capacity for memory: due to " + e); } } @@ -3499,14 +3470,14 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S // com.xensource.xenapi.Types$BadServerResponse // [HANDLE_INVALID, VM, // 3dde93f9-c1df-55a7-2cde-55e1dce431ab] - logger.info("Unable to get a vm PowerState due to " + e.toString() + ". We are retrying. Count: " + retry); + logger.info("Unable to get a vm PowerState due to " + e + ". We are retrying. Count: " + retry); try { Thread.sleep(3000); - } catch (final InterruptedException ex) { + } catch (final InterruptedException ignored) { } } catch (final XenAPIException e) { - final String msg = "Unable to get a vm PowerState due to " + e.toString(); + final String msg = "Unable to get a vm PowerState due to " + e; logger.warn(msg, e); break; } catch (final XmlRpcException e) { @@ -3520,7 +3491,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } public HashMap getVmStats(final Connection conn, final GetVmStatsCommand cmd, final List vmUUIDs, final String hostGuid) { - final HashMap vmResponseMap = new HashMap(); + final HashMap vmResponseMap = new HashMap<>(); for (final String vmUUID : vmUUIDs) { vmResponseMap.put(vmUUID, new VmStatsEntry(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "vm")); @@ -3561,7 +3532,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final String uuid = columnMetadataList[2]; final String param = columnMetadataList[3]; - if (type.equals("vm") && vmResponseMap.keySet().contains(uuid)) { + if (type.equals("vm") && vmResponseMap.containsKey(uuid)) { final VmStatsEntry vmStatsAnswer = vmResponseMap.get(uuid); vmStatsAnswer.setEntityType("vm"); @@ -3606,7 +3577,6 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S public String getVncUrl(final Connection conn, final VM vm) { VM.Record record; - Console c; try { record = vm.getRecord(conn); final Set consoles = record.consoles; @@ -3615,15 +3585,13 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.warn("There are no Consoles available to the vm : " + record.nameDescription); return null; } - final Iterator i = consoles.iterator(); - while (i.hasNext()) { - c = i.next(); - if (c.getProtocol(conn) == Types.ConsoleProtocol.RFB) { - return c.getLocation(conn); + for (Console console : consoles) { + if (console.getProtocol(conn) == Types.ConsoleProtocol.RFB) { + return console.getLocation(conn); } } } catch (final XenAPIException e) { - final String msg = "Unable to get console url due to " + e.toString(); + final String msg = "Unable to get console url due to " + e; logger.warn(msg, e); return null; } catch (final XmlRpcException e) { @@ -3638,7 +3606,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S return n.getChildNodes().item(0).getNodeValue(); } - public void handleSrAndVdiDetach(final String iqn, final Connection conn) throws Exception { + public void handleSrAndVdiDetach(final String iqn, final Connection conn) { final SR sr = getStorageRepository(conn, iqn); removeSR(conn, sr); @@ -3666,7 +3634,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { final VM.Record vmr = vm.getRecord(conn); - final List networks = new ArrayList(); + final List networks = new ArrayList<>(); for (final VIF vif : vmr.VIFs) { try { final VIF.Record rec = vif.getRecord(conn); @@ -3688,7 +3656,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } if (vm.getPowerState(conn) == VmPowerState.HALTED) { try { - vm.destroy(conn); + destroyVm(vm, conn, true); } catch (final Exception e) { logger.warn("VM destroy failed due to ", e); } @@ -3862,7 +3830,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S cmd.setDataCenter(Long.toString(_dcId)); cmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL); - String.format("StartUp command created for local storage [%s] of type [%s] on host [%s]", storagePoolInfo.getUuid(), storagePoolInfo.getPoolType(), _host.getUuid()); + logger.info("StartUp command created for local storage [{}] of type [{}] on host [{}]", storagePoolInfo.getUuid(), storagePoolInfo.getPoolType(), _host.getUuid()); return cmd; } @@ -3890,18 +3858,15 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S public boolean isDeviceUsed(final Connection conn, final VM vm, final Long deviceId) { // Figure out the disk number to attach the VM to - String msg = null; + String msg; try { final Set allowedVBDDevices = vm.getAllowedVBDDevices(conn); - if (allowedVBDDevices.contains(deviceId.toString())) { - return false; - } - return true; + return !allowedVBDDevices.contains(deviceId.toString()); } catch (final XmlRpcException e) { msg = "Catch XmlRpcException due to: " + e.getMessage(); logger.warn(msg, e); } catch (final XenAPIException e) { - msg = "Catch XenAPIException due to: " + e.toString(); + msg = "Catch XenAPIException due to: " + e; logger.warn(msg, e); } throw new CloudRuntimeException("When check deviceId " + msg); @@ -3929,9 +3894,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } final Connection conn = getConnection(); final XsLocalNetwork network = getNetworkByName(conn, nameTag); - if (network == null) { - return false; - } + return network != null; } return true; } @@ -3951,15 +3914,12 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S public boolean isXcp() { final Connection conn = getConnection(); final String result = callHostPlugin(conn, "ovstunnel", "is_xcp"); - if (result.equals("XCP")) { - return true; - } - return false; + return result.equals("XCP"); } boolean killCopyProcess(final Connection conn, final String nameLabel) { final String results = callHostPluginAsync(conn, "vmops", "kill_copy_process", 60, "namelabel", nameLabel); - String errMsg = null; + String errMsg; if (results == null || results.equals("false")) { errMsg = "kill_copy_process failed"; logger.warn(errMsg); @@ -3979,13 +3939,13 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } protected String logX(final XenAPIObject obj, final String msg) { - return new StringBuilder("Host ").append(_host.getIp()).append(" ").append(obj.toWireString()).append(": ").append(msg).toString(); + return "Host " + _host.getIp() + " " + obj.toWireString() + ": " + msg; } public void migrateVM(final Connection conn, final Host destHost, final VM vm, final String vmName) throws Exception { Task task = null; try { - final Map other = new HashMap(); + final Map other = new HashMap<>(); other.put("live", "true"); task = vm.poolMigrateAsync(conn, destHost, other); try { @@ -4009,7 +3969,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { task.destroy(conn); } catch (final Exception e1) { - logger.debug("unable to destroy task(" + task.toString() + ") on host(" + _host.getUuid() + ") due to " + e1.toString()); + logger.debug("unable to destroy task(" + task + ") on host(" + _host.getUuid() + ") due to " + e1); } } } @@ -4041,10 +4001,8 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S throw new CloudRuntimeException("Could not find ISO with URL: " + actualTemplateName); } return vdis.iterator().next(); - } catch (final XenAPIException e) { - throw new CloudRuntimeException("Unable to get pv iso: " + templateName + " due to " + e.toString()); } catch (final Exception e) { - throw new CloudRuntimeException("Unable to get pv iso: " + templateName + " due to " + e.toString()); + throw new CloudRuntimeException("Unable to get pv iso: " + templateName + " due to " + e); } } @@ -4094,7 +4052,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final Connection conn = getConnection(); final String result = callHostPlugin(conn, "ovsgre", "ovs_get_vm_log", "host_uuid", _host.getUuid()); final String[] logs = result != null ? result.split(";") : new String[0]; - final List> states = new ArrayList>(); + final List> states = new ArrayList<>(); for (final String log : logs) { final String[] info = log.split(","); if (info.length != 5) { @@ -4104,19 +4062,19 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S // ','.join([bridge, vmName, vmId, seqno, tag]) try { - states.add(new Pair(info[0], Long.parseLong(info[3]))); + states.add(new Pair<>(info[0], Long.parseLong(info[3]))); } catch (final NumberFormatException nfe) { - states.add(new Pair(info[0], -1L)); + states.add(new Pair<>(info[0], -1L)); } } return states; } public HashMap parseDefaultOvsRuleCommand(final String str) { - final HashMap cmd = new HashMap(); + final HashMap cmd = new HashMap<>(); final String[] sarr = str.split("/"); - for (int i = 0; i < sarr.length; i++) { - String c = sarr[i]; + for (String s : sarr) { + String c = s; c = c.startsWith("/") ? c.substring(1) : c; c = c.endsWith("/") ? c.substring(0, c.length() - 1) : c; final String[] p = c.split(";"); @@ -4142,7 +4100,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.debug("timeStamp in network doesn't start with CsCreateTime: " + timeStampStr); return null; } - return new Pair(Long.parseLong(tokens[1]), Integer.parseInt(tokens[2])); + return new Pair<>(Long.parseLong(tokens[1]), Integer.parseInt(tokens[2])); } private void pbdPlug(final Connection conn, final PBD pbd, final String uuid) { @@ -4152,7 +4110,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } pbd.plug(conn); } catch (final Exception e) { - final String msg = "PBD " + uuid + " is not attached! and PBD plug failed due to " + e.toString() + ". Please check this PBD in " + _host; + final String msg = "PBD " + uuid + " is not attached! and PBD plug failed due to " + e + ". Please check this PBD in " + _host; logger.warn(msg, e); throw new CloudRuntimeException(msg); } @@ -4162,11 +4120,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S String status; status = callHostPlugin(conn, "vmops", "pingdomr", "host", host, "port", port); - if (status == null || status.isEmpty()) { - return false; - } - - return true; + return status != null && !status.isEmpty(); } @@ -4179,13 +4133,13 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S return false; } } catch (final Exception e) { - logger.debug("cannot get host enabled status, host " + _host.getIp() + " due to " + e.toString(), e); + logger.debug("cannot get host enabled status, host " + _host.getIp() + " due to " + e, e); return false; } try { callHostPlugin(conn, "echo", "main"); } catch (final Exception e) { - logger.debug("cannot ping host " + _host.getIp() + " due to " + e.toString(), e); + logger.debug("cannot ping host " + _host.getIp() + " due to " + e, e); return false; } return true; @@ -4257,7 +4211,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final Set vbds = vm.getVBDs(conn); for (final VBD vbd : vbds) { final VBD.Record vbdr = vbd.getRecord(conn); - if (vbdr.type == Types.VbdType.CD && vbdr.empty == false && vbdr.userdevice.equals(_attachIsoDeviceNum)) { + if (vbdr.type == Types.VbdType.CD && !vbdr.empty && vbdr.userdevice.equals(_attachIsoDeviceNum)) { final VDI vdi = vbdr.VDI; final SR sr = vdi.getSR(conn); final Set pbds = sr.getPBDs(conn); @@ -4291,7 +4245,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S return null; } - final boolean isManaged = new Boolean(details.get(DiskTO.MANAGED)).booleanValue(); + final boolean isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); if (!isManaged) { return null; @@ -4301,7 +4255,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final Set srNameLabels = SR.getByNameLabel(conn, iqn); - if (srNameLabels.size() != 0) { + if (!srNameLabels.isEmpty()) { return null; } @@ -4320,10 +4274,9 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (StoragePoolType.NetworkFilesystem.toString().equalsIgnoreCase(protocoltype)) { final String poolid = storageHost + ":" + mountpoint; - final String namelable = mountpoint; final String volumedesc = storageHost + ":" + mountpoint; - return getNfsSR(conn, poolid, namelable, storageHost, mountpoint, volumedesc); + return getNfsSR(conn, poolid, mountpoint, storageHost, mountpoint, volumedesc); } else { return getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, false, SRType.LVMOISCSI.toString(), true); } @@ -4413,10 +4366,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S // If we are disassociating the last IP address in the VLAN, we // need // to remove a VIF - boolean addVif = false; - if (ip.isAdd() && correctVif == null) { - addVif = true; - } + boolean addVif = ip.isAdd() && correctVif == null; if (addVif) { // Add a new VIF to DomR @@ -4493,7 +4443,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S return new ExecutionResult(false, msg); } } catch (final Exception e) { - final String msg = "Prepare SetNetworkACL failed due to " + e.toString(); + final String msg = "Prepare SetNetworkACL failed due to " + e; logger.error(msg, e); return new ExecutionResult(false, msg); } @@ -4512,7 +4462,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S pubIp.setNicDevId(Integer.valueOf(correctVif.getDevice(conn))); } catch (final Exception e) { - final String msg = "Ip SNAT failure due to " + e.toString(); + final String msg = "Ip SNAT failure due to " + e; logger.error(msg, e); return new ExecutionResult(false, msg); } @@ -4549,7 +4499,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S nic.setDeviceId(Integer.parseInt(domrVif.getDevice(conn))); } catch (final Exception e) { - final String msg = "Creating guest network failed due to " + e.toString(); + final String msg = "Creating guest network failed due to " + e; logger.warn(msg, e); return new ExecutionResult(false, msg); } @@ -4572,11 +4522,11 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S throw new CloudRuntimeException("Reboot VM catch HandleInvalid and VM is not in RUNNING state"); } } catch (final XenAPIException e) { - logger.debug("Unable to Clean Reboot VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e.toString() + ", try hard reboot"); + logger.debug("Unable to Clean Reboot VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e + ", try hard reboot"); try { vm.hardReboot(conn); } catch (final Exception e1) { - final String msg = "Unable to hard Reboot VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e.toString(); + final String msg = "Unable to hard Reboot VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e; logger.warn(msg, e1); throw new CloudRuntimeException(msg); } @@ -4585,7 +4535,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { task.destroy(conn); } catch (final Exception e1) { - logger.debug("unable to destroy task(" + task.toString() + ") on host(" + _host.getUuid() + ") due to " + e1.toString()); + logger.debug("unable to destroy task(" + task + ") on host(" + _host.getUuid() + ") due to " + e1); } } } @@ -4609,7 +4559,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S removeSR(conn, sr); return; } catch (XenAPIException | XmlRpcException e) { - logger.warn(logX(sr, "Unable to get current operations " + e.toString()), e); + logger.warn(logX(sr, "Unable to get current operations " + e), e); } String msg = "Remove SR failed"; logger.warn(msg); @@ -4646,7 +4596,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S pbds = sr.getPBDs(conn); - if (pbds.size() == 0) { + if (pbds.isEmpty()) { if (logger.isDebugEnabled()) { logger.debug(logX(sr, "Forgetting")); } @@ -4666,7 +4616,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } } } catch (final XenAPIException e) { - logger.debug(logX(sr, "Catch XenAPIException: " + e.toString())); + logger.debug(logX(sr, "Catch XenAPIException: " + e)); } catch (final XmlRpcException e) { logger.debug(logX(sr, "Catch Exception: " + e.getMessage())); } @@ -4687,7 +4637,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final Set vdis = sr.getVDIs(conn); for (final VDI vdi : vdis) { final Map currentOperation = vdi.getCurrentOperations(conn); - if (currentOperation == null || currentOperation.size() == 0) { + if (currentOperation == null || currentOperation.isEmpty()) { continue; } if (waittime >= 1800000) { @@ -4698,13 +4648,13 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S waittime += 30000; try { Thread.sleep(30000); - } catch (final InterruptedException ex) { + } catch (final InterruptedException ignored) { } } removeSR(conn, sr); return null; } catch (final XenAPIException e) { - logger.warn(logX(sr, "Unable to get current operations " + e.toString()), e); + logger.warn(logX(sr, "Unable to get current operations " + e), e); } catch (final XmlRpcException e) { logger.warn(logX(sr, "Unable to get current operations " + e.getMessage()), e); } @@ -4719,7 +4669,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final String results = callHostPluginAsync(conn, "vmopsSnapshot", "revert_memory_snapshot", 10 * 60 * 1000, "snapshotUUID", vmSnapshot.getUuid(conn), "vmName", vmName, "oldVmUuid", oldVmUuid, "snapshotMemory", snapshotMemory.toString(), "hostUUID", hostUUID); - String errMsg = null; + String errMsg; if (results == null || results.isEmpty()) { errMsg = "revert_memory_snapshot return null"; } else { @@ -4750,7 +4700,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final Integer speed = vmSpec.getMinSpeed(); if (speed != null) { - int cpuWeight = _maxWeight; // cpu_weight + int cpuWeight; // cpu_weight // weight based allocation @@ -4760,7 +4710,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } if (vmSpec.getLimitCpuUse()) { - long utilization = 0; // max CPU cap, default is unlimited + long utilization; // max CPU cap, default is unlimited utilization = (int)(vmSpec.getMaxSpeed() * 0.99 * vmSpec.getCpus() / _host.getSpeed() * 100); // vm.addToVCPUsParamsLive(conn, "cap", // Long.toString(utilization)); currently xenserver doesnot @@ -4788,10 +4738,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S public boolean setIptables(final Connection conn) { final String result = callHostPlugin(conn, "vmops", "setIptables"); - if (result == null || result.isEmpty()) { - return false; - } - return true; + return result != null && !result.isEmpty(); } public void setIsOvs(final boolean isOvs) { @@ -4819,7 +4766,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } protected void setNicDevIdIfCorrectVifIsNotNull(final Connection conn, final IpAddressTO ip, final VIF correctVif) - throws InternalErrorException, BadServerResponse, XenAPIException, XmlRpcException { + throws InternalErrorException, XenAPIException, XmlRpcException { if (correctVif == null) { if (ip.isAdd()) { throw new InternalErrorException("Failed to find DomR VIF to associate IP with."); @@ -4841,7 +4788,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (!srRec.shared || !SRType.LVMOHBA.equals(srRec.type) && !SRType.LVMOISCSI.equals(srRec.type) && !SRType.NFS.equals(srRec.type)) { return srUuid; } - String result = null; + String result; final Host host = Host.getByUuid(conn, _host.getUuid()); final Set tags = host.getTags(conn); if (force || !tags.contains("cloud-heartbeat-" + srUuid)) { @@ -4877,12 +4824,12 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { final Network.Record rec = new Network.Record(); final Set networks = Network.getByNameLabel(conn, _linkLocalPrivateNetworkName); - Network linkLocal = null; + Network linkLocal; - if (networks.size() == 0) { + if (networks.isEmpty()) { rec.nameDescription = "link local network used by system vms"; rec.nameLabel = _linkLocalPrivateNetworkName; - final Map configs = new HashMap(); + final Map configs = new HashMap<>(); configs.put("ip_begin", NetUtils.getLinkLocalGateway()); configs.put("ip_end", NetUtils.getLinkLocalIpEnd()); configs.put("netmask", NetUtils.getLinkLocalNetMask()); @@ -4901,7 +4848,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final Pair vm = getControlDomain(conn); final VM dom0 = vm.first(); final Set vifs = dom0.getVIFs(conn); - if (vifs.size() != 0) { + if (!vifs.isEmpty()) { for (final VIF vif : vifs) { final Map otherConfig = vif.getOtherConfig(conn); if (otherConfig != null) { @@ -4923,7 +4870,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.debug("Failed to create link local network, no vif available"); return; } - final Map config = new HashMap(); + final Map config = new HashMap<>(); config.put("nameLabel", "link_local_network_vif"); vifr.otherConfig = config; vifr.MAC = "FE:FF:FF:FF:FF:FF"; @@ -4942,12 +4889,9 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S callHostPlugin(conn, "vmops", "setLinkLocalIP", "brName", brName); _host.setLinkLocalNetwork(linkLocal.getUuid(conn)); - } catch (final XenAPIException e) { + } catch (final XenAPIException | XmlRpcException e) { logger.warn("Unable to create local link network", e); - throw new CloudRuntimeException("Unable to create local link network due to " + e.toString(), e); - } catch (final XmlRpcException e) { - logger.warn("Unable to create local link network", e); - throw new CloudRuntimeException("Unable to create local link network due to " + e.toString(), e); + throw new CloudRuntimeException("Unable to create local link network due to " + e, e); } } @@ -5000,11 +4944,11 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S final String k = (String)entry.getKey(); final String v = (String)entry.getValue(); - assert k != null && k.length() > 0 && v != null && v.length() > 0 : "Problems with " + k + "=" + v; + assert k != null && !k.isEmpty() && v != null && !v.isEmpty() : "Problems with " + k + "=" + v; final String[] tokens = v.split(","); - String f = null; - if (tokens.length == 3 && tokens[0].length() > 0) { + String f; + if (tokens.length == 3 && !tokens[0].isEmpty()) { if (tokens[0].startsWith("/")) { f = tokens[0]; } else if (tokens[0].startsWith("~")) { @@ -5058,9 +5002,9 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S host.setTags(conn, hr.tags); return true; } catch (final XenAPIException e) { - final String msg = "XenServer setup failed due to " + e.toString(); + final String msg = "XenServer setup failed due to " + e; logger.warn(msg, e); - throw new CloudRuntimeException("Unable to get host information " + e.toString(), e); + throw new CloudRuntimeException("Unable to get host information " + e, e); } catch (final XmlRpcException e) { final String msg = "XenServer setup failed due to " + e.getMessage(); logger.warn(msg, e); @@ -5071,12 +5015,12 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S public synchronized Network setupvSwitchNetwork(final Connection conn) { try { if (_host.getVswitchNetwork() == null) { - Network vswitchNw = null; + Network vswitchNw; final Network.Record rec = new Network.Record(); final String nwName = Networks.BroadcastScheme.VSwitch.toString(); final Set networks = Network.getByNameLabel(conn, nwName); - if (networks.size() == 0) { + if (networks.isEmpty()) { rec.nameDescription = "vswitch network for " + nwName; rec.nameLabel = nwName; vswitchNw = Network.create(conn, rec); @@ -5086,11 +5030,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S _host.setVswitchNetwork(vswitchNw); } return _host.getVswitchNetwork(); - } catch (final BadServerResponse e) { - logger.error("Failed to setup vswitch network", e); - } catch (final XenAPIException e) { - logger.error("Failed to setup vswitch network", e); - } catch (final XmlRpcException e) { + } catch (final XmlRpcException | XenAPIException e) { logger.error("Failed to setup vswitch network", e); } @@ -5118,29 +5058,28 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S throw new CloudRuntimeException("Shutdown VM catch HandleInvalid and VM is not in HALTED state"); } } catch (final XenAPIException e) { - logger.debug("Unable to shutdown VM(" + vmName + ") with force=" + forcedStop + " on host(" + _host.getUuid() + ") due to " + e.toString()); + logger.debug("Unable to shutdown VM(" + vmName + ") with force=" + forcedStop + " on host(" + _host.getUuid() + ") due to " + e); try { VmPowerState state = vm.getPowerState(conn); if (state == VmPowerState.RUNNING) { try { vm.hardShutdown(conn); } catch (final Exception e1) { - logger.debug("Unable to hardShutdown VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e.toString()); + logger.debug("Unable to hardShutdown VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e); state = vm.getPowerState(conn); if (state == VmPowerState.RUNNING) { forceShutdownVM(conn, vm); } - return; } } else if (state == VmPowerState.HALTED) { - return; + // do nothing more } else { final String msg = "After cleanShutdown the VM status is " + state.toString() + ", that is not expected"; logger.warn(msg); throw new CloudRuntimeException(msg); } } catch (final Exception e1) { - final String msg = "Unable to hardShutdown VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e.toString(); + final String msg = "Unable to hardShutdown VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e; logger.warn(msg, e1); throw new CloudRuntimeException(msg); } @@ -5149,7 +5088,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { task.destroy(conn); } catch (final Exception e1) { - logger.debug("unable to destroy task(" + task.toString() + ") on host(" + _host.getUuid() + ") due to " + e1.toString()); + logger.debug("unable to destroy task(" + task + ") on host(" + _host.getUuid() + ") due to " + e1); } } } @@ -5184,7 +5123,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S throw new CloudRuntimeException("Start VM " + vmName + " catch BadAsyncResult and VM is not in RUNNING state"); } } catch (final XenAPIException e) { - final String msg = "Unable to start VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e.toString(); + final String msg = "Unable to start VM(" + vmName + ") on host(" + _host.getUuid() + ") due to " + e; logger.warn(msg, e); throw new CloudRuntimeException(msg); } finally { @@ -5192,7 +5131,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { task.destroy(conn); } catch (final Exception e1) { - logger.debug("unable to destroy task(" + task.toString() + ") on host(" + _host.getUuid() + ") due to " + e1.toString()); + logger.debug("unable to destroy task(" + task + ") on host(" + _host.getUuid() + ") due to " + e1); } } } @@ -5206,31 +5145,31 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { vm.hardShutdown(conn); } catch (final Exception e) { - final String msg = "VM hardshutdown failed due to " + e.toString(); + final String msg = "VM hardshutdown failed due to " + e; logger.warn(msg, e); } } if (vm.getPowerState(conn) == VmPowerState.HALTED) { try { - vm.destroy(conn); + destroyVm(vm, conn, true); } catch (final Exception e) { - final String msg = "VM destroy failed due to " + e.toString(); + final String msg = "VM destroy failed due to " + e; logger.warn(msg, e); } } } catch (final Exception e) { - final String msg = "VM getPowerState failed due to " + e.toString(); + final String msg = "VM getPowerState failed due to " + e; logger.warn(msg, e); } } if (mounts != null) { for (final Ternary mount : mounts) { final VDI vdi = mount.second(); - Set vbds = null; + Set vbds; try { vbds = vdi.getVBDs(conn); } catch (final Exception e) { - final String msg = "VDI getVBDS failed due to " + e.toString(); + final String msg = "VDI getVBDS failed due to " + e; logger.warn(msg, e); continue; } @@ -5239,7 +5178,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S vbd.unplug(conn); vbd.destroy(conn); } catch (final Exception e) { - final String msg = "VBD destroy failed due to " + e.toString(); + final String msg = "VBD destroy failed due to " + e; logger.warn(msg, e); } } @@ -5254,7 +5193,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } private HashMap> syncNetworkGroups(final Connection conn, final long id) { - final HashMap> states = new HashMap>(); + final HashMap> states = new HashMap<>(); final String result = callHostPlugin(conn, "vmops", "get_rule_logs_for_vms", "host_uuid", _host.getUuid()); logger.trace("syncNetworkGroups: id=" + id + " got: " + result); @@ -5266,9 +5205,9 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } // output = ','.join([vmName, vmID, vmIP, domID, signature, seqno]) try { - states.put(log[0], new Pair(Long.parseLong(log[1]), Long.parseLong(log[5]))); + states.put(log[0], new Pair<>(Long.parseLong(log[1]), Long.parseLong(log[5]))); } catch (final NumberFormatException nfe) { - states.put(log[0], new Pair(-1L, -1L)); + states.put(log[0], new Pair<>(-1L, -1L)); } } return states; @@ -5287,9 +5226,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S break; } ++count; - } catch (final XmlRpcException e) { - logger.debug("Waiting for host to come back: " + e.getMessage()); - } catch (final XenAPIException e) { + } catch (final XmlRpcException | XenAPIException e) { logger.debug("Waiting for host to come back: " + e.getMessage()); } catch (final InterruptedException e) { logger.debug("Gotta run"); @@ -5346,10 +5283,10 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.trace("Task " + task.getNameLabel(c) + " (" + task.getUuid(c) + ") is pending, sleeping for " + pollInterval + "ms"); } Thread.sleep(pollInterval); - } catch (final InterruptedException e) { + } catch (final InterruptedException ignored) { } if (System.currentTimeMillis() - beginTime > timeout) { - final String msg = "Async " + timeout / 1000 + " seconds timeout for task " + task.toString(); + final String msg = "Async " + timeout / 1000 + " seconds timeout for task " + task; logger.warn(msg); task.cancel(c); task.destroy(c); @@ -5382,11 +5319,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } // 3. attachIsoToVM - if (!attachConfigDriveIsoToVm(conn, vm)) { - return false; - } - - return true; + return attachConfigDriveIsoToVm(conn, vm); } public boolean createVmdataFiles(final String vmName, final List vmDataList, final String configDriveLabel) { @@ -5400,8 +5333,6 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S try { deleteLocalFolder("/tmp/" + isoPath); - } catch (final IOException e) { - logger.debug("Failed to delete the exiting config drive for vm " + vmName + " " + e.getMessage()); } catch (final Exception e) { logger.debug("Failed to delete the exiting config drive for vm " + vmName + " " + e.getMessage()); } @@ -5432,8 +5363,8 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S if (result && content != null && !content.isEmpty()) { File file = new File(folder + "/" + fileName + ".txt"); - try (OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file.getAbsoluteFile()), "UTF-8"); - BufferedWriter bw = new BufferedWriter(fw);) { + try (OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file.getAbsoluteFile()), StringUtils.getPreferredCharset()); + BufferedWriter bw = new BufferedWriter(fw)) { bw.write(content); logger.debug("created file: " + file + " in folder:" + folder); } catch (final IOException ex) { @@ -5447,7 +5378,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.debug("Created the vm data in " + isoPath); } - String s = null; + String s; try { final String cmd = "mkisofs -iso-level 3 -V " + configDriveLabel + " -o " + isoPath + vmName + ".iso " + isoPath; @@ -5533,11 +5464,8 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } srVdi = vdis.iterator().next(); - } catch (final XenAPIException e) { - logger.debug("Unable to get config drive iso: " + isoURL + " due to " + e.toString()); - return false; } catch (final Exception e) { - logger.debug("Unable to get config drive iso: " + isoURL + " due to " + e.toString()); + logger.debug("Unable to get config drive iso: " + isoURL + " due to " + e); return false; } @@ -5566,8 +5494,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S cfgDriveVbdr.userdevice = "autodetect"; cfgDriveVbdr.mode = Types.VbdMode.RO; cfgDriveVbdr.type = Types.VbdType.CD; - final VBD cfgDriveVBD = VBD.create(conn, cfgDriveVbdr); - isoVBD = cfgDriveVBD; + isoVBD = VBD.create(conn, cfgDriveVbdr); logger.debug("Created CD-ROM VBD for VM: " + vm); } @@ -5602,7 +5529,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } try { - final Map deviceConfig = new HashMap(); + final Map deviceConfig = new HashMap<>(); final com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_host.getIp(), 22); try { @@ -5626,7 +5553,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S deviceConfig.put("legacy_mode", "true"); final Host host = Host.getByUuid(conn, _host.getUuid()); final String type = SRType.ISO.toString(); - sr = SR.create(conn, host, deviceConfig, new Long(0), _configDriveIsopath, "iso", type, "iso", false, new HashMap()); + sr = SR.create(conn, host, deviceConfig, 0L, _configDriveIsopath, "iso", type, "iso", false, new HashMap<>()); sr.setNameLabel(conn, srName); sr.setNameDescription(conn, deviceConfig.get("location")); @@ -5635,7 +5562,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.debug("Config drive ISO SR at the path " + _configDriveIsopath + " got created in host " + _host); return sr; } catch (final XenAPIException e) { - final String msg = "createLocalIsoSR failed! mountpoint " + e.toString(); + final String msg = "createLocalIsoSR failed! mountpoint " + e; logger.warn(msg, e); throw new CloudRuntimeException(msg, e); } catch (final Exception e) { @@ -5662,7 +5589,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } } - protected SR getSRByNameLabel(Connection conn, String name) throws BadServerResponse, XenAPIException, XmlRpcException { + protected SR getSRByNameLabel(Connection conn, String name) throws XenAPIException, XmlRpcException { Set srs = SR.getByNameLabel(conn, name); SR ressr = null; for (SR sr : srs) { @@ -5769,7 +5696,7 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S } String mountPoint = "/var/run/sr-mount/" + sr.getUuid(conn); boolean pathExists = true; - SFTPv3FileAttributes fileAttr = null; + SFTPv3FileAttributes fileAttr; int count = 0; List names = new ArrayList<>(); List paths = new ArrayList<>(); @@ -5826,7 +5753,6 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S String nfsVersion = cmd.getNfsVersion(); String localDir = null; - boolean success; // Mount Secondary storage String secondaryStorageMountPath = null; @@ -5879,4 +5805,20 @@ public abstract class CitrixResourceBase extends ServerResourceBase implements S logger.warn(errMsg); } } + + public boolean isDestroyHaltedVms() { + ComparableVersion version = new ComparableVersion(getHost().getProductVersion()); + return version.compareTo(new ComparableVersion("8.0")) < 0; + } + + public void destroyVm(VM vm, Connection connection, boolean forced) throws XenAPIException, XmlRpcException { + if (!isDestroyHaltedVms() && !forced) { + return; + } + vm.destroy(connection); + } + + public void destroyVm(VM vm, Connection connection) throws XenAPIException, XmlRpcException { + destroyVm(vm, connection, false); + } } diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56/XenServer56FenceCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56/XenServer56FenceCommandWrapper.java index c76059640b3..0fc70741076 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56/XenServer56FenceCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56/XenServer56FenceCommandWrapper.java @@ -54,7 +54,7 @@ public final class XenServer56FenceCommandWrapper extends CommandWrapper smConfig = vdi.getSmConfig(conn); for (final String key : smConfig.keySet()) { diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCreateVMSnapshotCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCreateVMSnapshotCommandWrapper.java index 85cfa5d8aa8..89d6e07e5f1 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCreateVMSnapshotCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCreateVMSnapshotCommandWrapper.java @@ -69,7 +69,7 @@ public final class CitrixCreateVMSnapshotCommandWrapper extends CommandWrapper vmSnapshots = VM.getByNameLabel(conn, command.getTarget().getSnapshotName()); - if (vmSnapshots == null || vmSnapshots.size() > 0) { + if (vmSnapshots == null || !vmSnapshots.isEmpty()) { return new CreateVMSnapshotAnswer(command, command.getTarget(), command.getVolumeTOs()); } @@ -98,6 +98,7 @@ public final class CitrixCreateVMSnapshotCommandWrapper extends CommandWrapper vbds = vmSnapshot.getVBDs(conn); for (final VBD vbd : vbds) { final VBD.Record vbdr = vbd.getRecord(conn); @@ -176,16 +177,14 @@ public final class CitrixCreateVMSnapshotCommandWrapper extends CommandWrapper vmSnapshots = VM.getByNameLabel(conn, command.getTarget().getSnapshotName()); - if (vmSnapshots == null || vmSnapshots.size() == 0) { + if (vmSnapshots == null || vmSnapshots.isEmpty()) { return new RevertToVMSnapshotAnswer(command, false, "Cannot find vmSnapshot with name: " + command.getTarget().getSnapshotName()); } @@ -66,6 +66,7 @@ public final class CitrixRevertToVMSnapshotCommandWrapper extends CommandWrapper try { vm = citrixResourceBase.getVM(conn, vmName); } catch (final Exception e) { + logger.debug("Failed to find VM with name: {} due to:", vmName, e); vm = citrixResourceBase.createWorkingVM(conn, vmName, command.getGuestOSType(), command.getPlatformEmulator(), listVolumeTo); } @@ -77,7 +78,7 @@ public final class CitrixRevertToVMSnapshotCommandWrapper extends CommandWrapper citrixResourceBase.revertToSnapshot(conn, vmSnapshot, vmName, vm.getUuid(conn), snapshotMemory, citrixResourceBase.getHost().getUuid()); vm = citrixResourceBase.getVM(conn, vmName); final Set vbds = vm.getVBDs(conn); - final Map vdiMap = new HashMap(); + final Map vdiMap = new HashMap<>(); // get vdi:vbdr to a map for (final VBD vbd : vbds) { final VBD.Record vbdr = vbd.getRecord(conn); @@ -88,7 +89,7 @@ public final class CitrixRevertToVMSnapshotCommandWrapper extends CommandWrapper } if (!snapshotMemory) { - vm.destroy(conn); + citrixResourceBase.destroyVm(vm, conn); vmState = PowerState.PowerOff; } else { vmState = PowerState.PowerOn; @@ -103,7 +104,7 @@ public final class CitrixRevertToVMSnapshotCommandWrapper extends CommandWrapper return new RevertToVMSnapshotAnswer(command, listVolumeTo, vmState); } catch (final Exception e) { - logger.error("revert vm " + vmName + " to snapshot " + command.getTarget().getSnapshotName() + " failed due to " + e.getMessage()); + logger.error("revert vm {} to snapshot {} failed due to {}", vmName, command.getTarget().getSnapshotName(), e.getMessage()); return new RevertToVMSnapshotAnswer(command, false, e.getMessage()); } } diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java index 33d4eaf6e77..2f3fb049339 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java @@ -73,7 +73,7 @@ public final class CitrixStartCommandWrapper extends CommandWrapper hosts = hostDao.listHostsByMs(msId); + for (HostVO host : hosts) { + if (host != null) { + host.setLastManagementServerId(msId); + hostDao.update(host.getId(), host); + } + } + } + @Override public void registerListener(ManagementServerMaintenanceListener listener) { synchronized (_listeners) { @@ -124,6 +146,26 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen } } + @Override + public void onPreparingForMaintenance() { + synchronized (_listeners) { + for (final ManagementServerMaintenanceListener listener : _listeners) { + logger.info("Invoke, on preparing for maintenance for listener " + listener.getClass()); + listener.onManagementServerPreparingForMaintenance(); + } + } + } + + @Override + public void onCancelPreparingForMaintenance() { + synchronized (_listeners) { + for (final ManagementServerMaintenanceListener listener : _listeners) { + logger.info("Invoke, on cancel preparing for maintenance for listener " + listener.getClass()); + listener.onManagementServerCancelPreparingForMaintenance(); + } + } + } + @Override public void onMaintenance() { synchronized (_listeners) { @@ -243,6 +285,7 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen this.maintenanceStartTime = System.currentTimeMillis(); this.lbAlgorithm = lbAlorithm; jobManager.disableAsyncJobs(); + onPreparingForMaintenance(); waitForPendingJobs(); } @@ -257,8 +300,13 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen jobManager.enableAsyncJobs(); cancelWaitForPendingJobs(); ManagementServerHostVO msHost = msHostDao.findByMsid(ManagementServerNode.getManagementServerId()); - if (msHost != null && State.Maintenance.equals(msHost.getState())) { - onCancelMaintenance(); + if (msHost != null) { + if (State.PreparingForMaintenance.equals(msHost.getState())) { + onCancelPreparingForMaintenance(); + } + if (State.Maintenance.equals(msHost.getState())) { + onCancelMaintenance(); + } } } @@ -284,6 +332,7 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen } @Override + @ActionEvent(eventType = EventTypes.EVENT_MS_SHUTDOWN_PREPARE, eventDescription = "preparing for shutdown") public ManagementServerMaintenanceResponse prepareForShutdown(PrepareForShutdownCmd cmd) { ManagementServerHostVO msHost = msHostDao.findById(cmd.getManagementServerId()); if (msHost == null) { @@ -294,19 +343,18 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen throw new CloudRuntimeException("Management server is not in the right state to prepare for shutdown"); } + checkAnyMsInPreparingStates("prepare for shutdown"); + final Command[] cmds = new Command[1]; cmds[0] = new PrepareForShutdownManagementServerHostCommand(msHost.getMsid()); - String result = clusterManager.execute(String.valueOf(msHost.getMsid()), 0, gson.toJson(cmds), true); - logger.info("PrepareForShutdownCmd result : " + result); - if (!result.startsWith("Success")) { - throw new CloudRuntimeException(result); - } + executeCmd(msHost, cmds); msHostDao.updateState(msHost.getId(), State.PreparingForShutDown); return prepareMaintenanceResponse(cmd.getManagementServerId()); } @Override + @ActionEvent(eventType = EventTypes.EVENT_MS_SHUTDOWN, eventDescription = "triggering shutdown") public ManagementServerMaintenanceResponse triggerShutdown(TriggerShutdownCmd cmd) { ManagementServerHostVO msHost = msHostDao.findById(cmd.getManagementServerId()); if (msHost == null) { @@ -319,22 +367,20 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen } if (State.Up.equals(msHost.getState())) { + checkAnyMsInPreparingStates("trigger shutdown"); msHostDao.updateState(msHost.getId(), State.PreparingForShutDown); } final Command[] cmds = new Command[1]; cmds[0] = new TriggerShutdownManagementServerHostCommand(msHost.getMsid()); - String result = clusterManager.execute(String.valueOf(msHost.getMsid()), 0, gson.toJson(cmds), true); - logger.info("TriggerShutdownCmd result : " + result); - if (!result.startsWith("Success")) { - throw new CloudRuntimeException(result); - } + executeCmd(msHost, cmds); msHostDao.updateState(msHost.getId(), State.ShuttingDown); return prepareMaintenanceResponse(cmd.getManagementServerId()); } @Override + @ActionEvent(eventType = EventTypes.EVENT_MS_SHUTDOWN_CANCEL, eventDescription = "cancelling shutdown") public ManagementServerMaintenanceResponse cancelShutdown(CancelShutdownCmd cmd) { ManagementServerHostVO msHost = msHostDao.findById(cmd.getManagementServerId()); if (msHost == null) { @@ -347,17 +393,14 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen final Command[] cmds = new Command[1]; cmds[0] = new CancelShutdownManagementServerHostCommand(msHost.getMsid()); - String result = clusterManager.execute(String.valueOf(msHost.getMsid()), 0, gson.toJson(cmds), true); - logger.info("CancelShutdownCmd result : " + result); - if (!result.startsWith("Success")) { - throw new CloudRuntimeException(result); - } + executeCmd(msHost, cmds); msHostDao.updateState(msHost.getId(), State.Up); return prepareMaintenanceResponse(cmd.getManagementServerId()); } @Override + @ActionEvent(eventType = EventTypes.EVENT_MS_MAINTENANCE_PREPARE, eventDescription = "preparing for maintenance") public ManagementServerMaintenanceResponse prepareForMaintenance(PrepareForMaintenanceCmd cmd) { if (StringUtils.isNotBlank(cmd.getAlgorithm())) { indirectAgentLB.checkLBAlgorithmName(cmd.getAlgorithm()); @@ -381,10 +424,7 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen throw new CloudRuntimeException("Management server is not in the right state to prepare for maintenance"); } - final List preparingForMaintenanceMsList = msHostDao.listBy(State.PreparingForMaintenance); - if (CollectionUtils.isNotEmpty(preparingForMaintenanceMsList)) { - throw new CloudRuntimeException("Cannot prepare for maintenance, there are other management servers preparing for maintenance"); - } + checkAnyMsInPreparingStates("prepare for maintenance"); if (indirectAgentLB.haveAgentBasedHosts(msHost.getMsid())) { List indirectAgentMsList = indirectAgentLB.getManagementServerList(); @@ -396,23 +436,16 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen } } - List lastAgents = hostDao.listByMs(cmd.getManagementServerId()); - agentMgr.setLastAgents(lastAgents); - final Command[] cmds = new Command[1]; cmds[0] = new PrepareForMaintenanceManagementServerHostCommand(msHost.getMsid(), cmd.getAlgorithm()); - String result = clusterManager.execute(String.valueOf(msHost.getMsid()), 0, gson.toJson(cmds), true); - logger.info("PrepareForMaintenanceCmd result : " + result); - if (!result.startsWith("Success")) { - agentMgr.setLastAgents(null); - throw new CloudRuntimeException(result); - } + executeCmd(msHost, cmds); msHostDao.updateState(msHost.getId(), State.PreparingForMaintenance); return prepareMaintenanceResponse(cmd.getManagementServerId()); } @Override + @ActionEvent(eventType = EventTypes.EVENT_MS_MAINTENANCE_CANCEL, eventDescription = "cancelling maintenance") public ManagementServerMaintenanceResponse cancelMaintenance(CancelMaintenanceCmd cmd) { ManagementServerHostVO msHost = msHostDao.findById(cmd.getManagementServerId()); if (msHost == null) { @@ -425,15 +458,29 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen final Command[] cmds = new Command[1]; cmds[0] = new CancelMaintenanceManagementServerHostCommand(msHost.getMsid()); - String result = clusterManager.execute(String.valueOf(msHost.getMsid()), 0, gson.toJson(cmds), true); - logger.info("CancelMaintenanceCmd result : " + result); + executeCmd(msHost, cmds); + + msHostDao.updateState(msHost.getId(), State.Up); + return prepareMaintenanceResponse(cmd.getManagementServerId()); + } + + private void executeCmd(ManagementServerHostVO msHost, Command[] cmds) { + if (msHost == null) { + throw new CloudRuntimeException("Management server node not specified, to execute the cmd"); + } + if (cmds == null || cmds.length <= 0) { + throw new CloudRuntimeException(String.format("Cmd not specified, to execute on the management server node %s", msHost)); + } + String result = clusterManager.execute(String.valueOf(msHost.getMsid()), 0, gson.toJson(cmds), false); + if (result == null) { + String msg = String.format("Unable to reach or execute %s on the management server node: %s", cmds[0], msHost); + logger.warn(msg); + throw new CloudRuntimeException(msg); + } + logger.info(String.format("Cmd %s - result: %s", cmds[0], result)); if (!result.startsWith("Success")) { throw new CloudRuntimeException(result); } - - msHostDao.updateState(msHost.getId(), State.Up); - agentMgr.setLastAgents(null); - return prepareMaintenanceResponse(cmd.getManagementServerId()); } @Override @@ -445,9 +492,17 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen if (msHost == null) { msHost = msHostDao.findByMsid(ManagementServerNode.getManagementServerId()); } + onCancelPreparingForMaintenance(); msHostDao.updateState(msHost.getId(), State.Up); } + private void checkAnyMsInPreparingStates(String operation) { + final List preparingForMaintenanceOrShutDownMsList = msHostDao.listBy(State.PreparingForMaintenance, State.PreparingForShutDown); + if (CollectionUtils.isNotEmpty(preparingForMaintenanceOrShutDownMsList)) { + throw new CloudRuntimeException(String.format("Cannot %s, there are other management servers preparing for maintenance/shutdown", operation)); + } + } + private ManagementServerMaintenanceResponse prepareMaintenanceResponse(Long managementServerId) { ManagementServerHostVO msHost; Long[] msIds; @@ -465,8 +520,8 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen boolean maintenanceInitiatedForMS = Arrays.asList(maintenanceStates).contains(msHost.getState()); boolean shutdownTriggeredForMS = Arrays.asList(shutdownStates).contains(msHost.getState()); msIds = new Long[]{msHost.getMsid()}; - List agents = hostDao.listByMs(managementServerId); - long agentsCount = hostDao.countByMs(managementServerId); + List agents = hostDao.listByMs(msHost.getMsid()); + long agentsCount = agents.size(); long pendingJobCount = countPendingJobs(msIds); return new ManagementServerMaintenanceResponse(msHost.getUuid(), msHost.getState(), maintenanceInitiatedForMS, shutdownTriggeredForMS, pendingJobCount == 0, pendingJobCount, agentsCount, agents); } @@ -535,7 +590,6 @@ public class ManagementServerMaintenanceManagerImpl extends ManagerBase implemen // No more pending jobs. Good to terminate if (managementServerMaintenanceManager.isShutdownTriggered()) { logger.info("MS is Shutting Down Now"); - // update state to down ? System.exit(0); } if (managementServerMaintenanceManager.isPreparingForMaintenance()) { diff --git a/plugins/maintenance/src/test/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManagerImplTest.java b/plugins/maintenance/src/test/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManagerImplTest.java index 8e1c09bf995..dc14124d018 100644 --- a/plugins/maintenance/src/test/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManagerImplTest.java +++ b/plugins/maintenance/src/test/java/org/apache/cloudstack/maintenance/ManagementServerMaintenanceManagerImplTest.java @@ -17,7 +17,23 @@ package org.apache.cloudstack.maintenance; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.agent.lb.IndirectAgentLB; +import org.apache.cloudstack.api.command.CancelMaintenanceCmd; +import org.apache.cloudstack.api.command.CancelShutdownCmd; +import org.apache.cloudstack.api.command.PrepareForMaintenanceCmd; +import org.apache.cloudstack.api.command.PrepareForShutdownCmd; +import org.apache.cloudstack.api.command.TriggerShutdownCmd; import org.apache.cloudstack.framework.jobs.AsyncJobManager; +import org.apache.cloudstack.management.ManagementServerHost; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -27,6 +43,11 @@ import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; +import com.cloud.agent.AgentManager; +import com.cloud.cluster.ClusterManager; +import com.cloud.cluster.ManagementServerHostVO; +import com.cloud.cluster.dao.ManagementServerHostDao; +import com.cloud.host.dao.HostDao; import com.cloud.utils.exception.CloudRuntimeException; @@ -40,6 +61,21 @@ public class ManagementServerMaintenanceManagerImplTest { @Mock AsyncJobManager jobManagerMock; + @Mock + IndirectAgentLB indirectAgentLBMock; + + @Mock + AgentManager agentManagerMock; + + @Mock + ClusterManager clusterManagerMock; + + @Mock + HostDao hostDao; + + @Mock + ManagementServerHostDao msHostDao; + private long prepareCountPendingJobs() { long expectedCount = 1L; Mockito.doReturn(expectedCount).when(jobManagerMock).countPendingNonPseudoJobs(1L); @@ -53,13 +89,6 @@ public class ManagementServerMaintenanceManagerImplTest { Assert.assertEquals(expectedCount, count); } - @Test - public void cancelShutdown() { - Assert.assertThrows(CloudRuntimeException.class, () -> { - spy.cancelShutdown(); - }); - } - @Test public void prepareForShutdown() { Mockito.doNothing().when(jobManagerMock).disableAsyncJobs(); @@ -74,4 +103,463 @@ public class ManagementServerMaintenanceManagerImplTest { spy.cancelShutdown(); Mockito.verify(jobManagerMock).enableAsyncJobs(); } + + @Test + public void cancelShutdown() { + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.cancelShutdown(); + }); + } + + @Test + public void triggerShutdown() { + Mockito.doNothing().when(jobManagerMock).disableAsyncJobs(); + Mockito.lenient().when(spy.isShutdownTriggered()).thenReturn(false); + spy.triggerShutdown(); + Mockito.verify(jobManagerMock).disableAsyncJobs(); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.triggerShutdown(); + }); + } + + @Test + public void prepareForShutdownCmdNoMsHost() { + Mockito.when(msHostDao.findById(1L)).thenReturn(null); + PrepareForShutdownCmd cmd = mock(PrepareForShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForShutdown(cmd); + }); + } + + @Test + public void prepareForShutdownCmdMsHostWithNonUpState() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Maintenance); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost); + PrepareForShutdownCmd cmd = mock(PrepareForShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForShutdown(cmd); + }); + } + + @Test + public void prepareForShutdownCmdOtherMsHostsInPreparingState() { + ManagementServerHostVO msHost1 = mock(ManagementServerHostVO.class); + Mockito.when(msHost1.getState()).thenReturn(ManagementServerHost.State.Up); + ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class); + List msHostList = new ArrayList<>(); + msHostList.add(msHost2); + Mockito.when(msHostDao.listBy(any())).thenReturn(msHostList); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1); + PrepareForShutdownCmd cmd = mock(PrepareForShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForShutdown(cmd); + }); + } + + @Test + public void prepareForShutdownCmdNullResponseFromClusterManager() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Up); + List msHostList = new ArrayList<>(); + Mockito.when(msHostDao.listBy(any())).thenReturn(msHostList); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost); + PrepareForShutdownCmd cmd = mock(PrepareForShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn(null); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForShutdown(cmd); + }); + } + + @Test + public void prepareForShutdownCmdFailedResponseFromClusterManager() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Up); + List msHostList = new ArrayList<>(); + Mockito.when(msHostDao.listBy(any())).thenReturn(msHostList); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost); + PrepareForShutdownCmd cmd = mock(PrepareForShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn("Failed"); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForShutdown(cmd); + }); + } + + @Test + public void prepareForShutdownCmdSuccessResponseFromClusterManager() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Up); + Mockito.when(msHostDao.listBy(any())).thenReturn(new ArrayList<>()); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost); + Mockito.when(hostDao.listByMs(anyLong())).thenReturn(new ArrayList<>()); + PrepareForShutdownCmd cmd = mock(PrepareForShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn("Success"); + + spy.prepareForShutdown(cmd); + Mockito.verify(clusterManagerMock, Mockito.times(1)).execute(anyString(), anyLong(), anyString(), anyBoolean()); + } + + @Test + public void cancelShutdownCmdNoMsHost() { + Mockito.when(msHostDao.findById(1L)).thenReturn(null); + CancelShutdownCmd cmd = mock(CancelShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.cancelShutdown(cmd); + }); + } + + @Test + public void cancelShutdownCmdMsHostNotInShutdownState() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Up); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost); + CancelShutdownCmd cmd = mock(CancelShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.cancelShutdown(cmd); + }); + } + + @Test + public void cancelShutdownCmd() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.ReadyToShutDown); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost); + CancelShutdownCmd cmd = mock(CancelShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn("Success"); + + spy.cancelShutdown(cmd); + Mockito.verify(clusterManagerMock, Mockito.times(1)).execute(anyString(), anyLong(), anyString(), anyBoolean()); + } + + @Test + public void triggerShutdownCmdNoMsHost() { + Mockito.when(msHostDao.findById(1L)).thenReturn(null); + TriggerShutdownCmd cmd = mock(TriggerShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.triggerShutdown(cmd); + }); + } + + @Test + public void triggerShutdownCmdMsHostWithNotRightState() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.PreparingForMaintenance); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost); + TriggerShutdownCmd cmd = mock(TriggerShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.triggerShutdown(cmd); + }); + } + + @Test + public void triggerShutdownCmdMsInUpStateAndOtherMsHostsInPreparingState() { + ManagementServerHostVO msHost1 = mock(ManagementServerHostVO.class); + Mockito.when(msHost1.getState()).thenReturn(ManagementServerHost.State.Up); + ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class); + List msHostList = new ArrayList<>(); + msHostList.add(msHost2); + Mockito.when(msHostDao.listBy(any())).thenReturn(msHostList); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1); + TriggerShutdownCmd cmd = mock(TriggerShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.triggerShutdown(cmd); + }); + } + + @Test + public void triggerShutdownCmd() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.ReadyToShutDown); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost); + TriggerShutdownCmd cmd = mock(TriggerShutdownCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn("Success"); + + spy.triggerShutdown(cmd); + Mockito.verify(clusterManagerMock, Mockito.times(1)).execute(anyString(), anyLong(), anyString(), anyBoolean()); + } + + @Test + public void prepareForMaintenanceAndCancelFromMaintenanceState() { + Mockito.doNothing().when(jobManagerMock).disableAsyncJobs(); + spy.prepareForMaintenance("static"); + Mockito.verify(jobManagerMock).disableAsyncJobs(); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForMaintenance("static"); + }); + + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Maintenance); + Mockito.when(msHostDao.findByMsid(anyLong())).thenReturn(msHost); + Mockito.doNothing().when(jobManagerMock).enableAsyncJobs(); + spy.cancelMaintenance(); + Mockito.verify(jobManagerMock).enableAsyncJobs(); + Mockito.verify(spy, Mockito.times(1)).onCancelMaintenance(); + } + + @Test + public void prepareForMaintenanceAndCancelFromPreparingForMaintenanceState() { + Mockito.doNothing().when(jobManagerMock).disableAsyncJobs(); + spy.prepareForMaintenance("static"); + Mockito.verify(jobManagerMock).disableAsyncJobs(); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForMaintenance("static"); + }); + + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.PreparingForMaintenance); + Mockito.when(msHostDao.findByMsid(anyLong())).thenReturn(msHost); + Mockito.doNothing().when(jobManagerMock).enableAsyncJobs(); + spy.cancelMaintenance(); + Mockito.verify(jobManagerMock).enableAsyncJobs(); + Mockito.verify(spy, Mockito.times(1)).onCancelPreparingForMaintenance(); + } + + @Test + public void cancelMaintenance() { + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.cancelMaintenance(); + }); + } + + @Test + public void cancelPreparingForMaintenance() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHostDao.findByMsid(anyLong())).thenReturn(msHost); + + spy.cancelPreparingForMaintenance(null); + Mockito.verify(jobManagerMock).enableAsyncJobs(); + Mockito.verify(spy, Mockito.times(1)).onCancelPreparingForMaintenance(); + } + + @Test + public void prepareForMaintenanceCmdNoOtherMsHostsWithUpState() { + Mockito.when(msHostDao.listBy(any())).thenReturn(new ArrayList<>()); + PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class); + Mockito.when(cmd.getAlgorithm()).thenReturn("test algorithm"); + Mockito.doNothing().when(indirectAgentLBMock).checkLBAlgorithmName(anyString()); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForMaintenance(cmd); + }); + } + + @Test + public void prepareForMaintenanceCmdOnlyOneMsHostsWithUpState() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + List msHostList = new ArrayList<>(); + msHostList.add(msHost); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.Up)).thenReturn(msHostList); + PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class); + Mockito.when(cmd.getAlgorithm()).thenReturn("test algorithm"); + Mockito.doNothing().when(indirectAgentLBMock).checkLBAlgorithmName(anyString()); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForMaintenance(cmd); + }); + } + + @Test + public void prepareForMaintenanceCmdNoMsHost() { + ManagementServerHostVO msHost1 = mock(ManagementServerHostVO.class); + ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class); + List msHostList = new ArrayList<>(); + msHostList.add(msHost1); + msHostList.add(msHost2); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.Up)).thenReturn(msHostList); + Mockito.when(msHostDao.findById(1L)).thenReturn(null); + PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForMaintenance(cmd); + }); + } + + @Test + public void prepareForMaintenanceCmdMsHostWithNonUpState() { + ManagementServerHostVO msHost1 = mock(ManagementServerHostVO.class); + Mockito.when(msHost1.getState()).thenReturn(ManagementServerHost.State.Maintenance); + ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class); + List msHostList = new ArrayList<>(); + msHostList.add(msHost1); + msHostList.add(msHost2); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.Up)).thenReturn(msHostList); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1); + PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForMaintenance(cmd); + }); + } + + @Test + public void prepareForMaintenanceCmdOtherMsHostsInPreparingState() { + ManagementServerHostVO msHost1 = mock(ManagementServerHostVO.class); + Mockito.when(msHost1.getState()).thenReturn(ManagementServerHost.State.Up); + ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class); + List msHostList1 = new ArrayList<>(); + msHostList1.add(msHost1); + msHostList1.add(msHost2); + ManagementServerHostVO msHost3 = mock(ManagementServerHostVO.class); + List msHostList2 = new ArrayList<>(); + msHostList2.add(msHost3); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.Up)).thenReturn(msHostList1); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.PreparingForMaintenance, ManagementServerHost.State.PreparingForShutDown)).thenReturn(msHostList2); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1); + PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForMaintenance(cmd); + }); + } + + @Test + public void prepareForMaintenanceCmdNoIndirectMsHosts() { + ManagementServerHostVO msHost1 = mock(ManagementServerHostVO.class); + Mockito.when(msHost1.getState()).thenReturn(ManagementServerHost.State.Up); + ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class); + List msHostList = new ArrayList<>(); + msHostList.add(msHost1); + msHostList.add(msHost2); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.Up)).thenReturn(msHostList); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.PreparingForMaintenance, ManagementServerHost.State.PreparingForShutDown)).thenReturn(new ArrayList<>()); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1); + Mockito.when(msHostDao.listNonUpStateMsIPs()).thenReturn(new ArrayList<>()); + PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong())).thenReturn(true); + Mockito.when(indirectAgentLBMock.getManagementServerList()).thenReturn(new ArrayList<>()); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForMaintenance(cmd); + }); + } + + @Test + public void prepareForMaintenanceCmdNullResponseFromClusterManager() { + ManagementServerHostVO msHost1 = mock(ManagementServerHostVO.class); + Mockito.when(msHost1.getState()).thenReturn(ManagementServerHost.State.Up); + ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class); + List msHostList = new ArrayList<>(); + msHostList.add(msHost1); + msHostList.add(msHost2); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.Up)).thenReturn(msHostList); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.PreparingForMaintenance, ManagementServerHost.State.PreparingForShutDown)).thenReturn(new ArrayList<>()); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1); + PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong())).thenReturn(false); + Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn(null); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForMaintenance(cmd); + }); + } + + @Test + public void prepareForMaintenanceCmdFailedResponseFromClusterManager() { + ManagementServerHostVO msHost1 = mock(ManagementServerHostVO.class); + Mockito.when(msHost1.getState()).thenReturn(ManagementServerHost.State.Up); + ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class); + List msHostList = new ArrayList<>(); + msHostList.add(msHost1); + msHostList.add(msHost2); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.Up)).thenReturn(msHostList); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.PreparingForMaintenance, ManagementServerHost.State.PreparingForShutDown)).thenReturn(new ArrayList<>()); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1); + PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong())).thenReturn(false); + Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn("Failed"); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.prepareForMaintenance(cmd); + }); + } + + @Test + public void prepareForMaintenanceCmdSuccessResponseFromClusterManager() { + ManagementServerHostVO msHost1 = mock(ManagementServerHostVO.class); + Mockito.when(msHost1.getState()).thenReturn(ManagementServerHost.State.Up); + ManagementServerHostVO msHost2 = mock(ManagementServerHostVO.class); + List msHostList = new ArrayList<>(); + msHostList.add(msHost1); + msHostList.add(msHost2); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.Up)).thenReturn(msHostList); + Mockito.when(msHostDao.listBy(ManagementServerHost.State.PreparingForMaintenance, ManagementServerHost.State.PreparingForShutDown)).thenReturn(new ArrayList<>()); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost1); + PrepareForMaintenanceCmd cmd = mock(PrepareForMaintenanceCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + Mockito.when(indirectAgentLBMock.haveAgentBasedHosts(anyLong())).thenReturn(false); + Mockito.when(hostDao.listByMs(anyLong())).thenReturn(new ArrayList<>()); + Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn("Success"); + + spy.prepareForMaintenance(cmd); + Mockito.verify(clusterManagerMock, Mockito.times(1)).execute(anyString(), anyLong(), anyString(), anyBoolean()); + } + + @Test + public void cancelMaintenanceCmdNoMsHost() { + Mockito.when(msHostDao.findById(1L)).thenReturn(null); + CancelMaintenanceCmd cmd = mock(CancelMaintenanceCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.cancelMaintenance(cmd); + }); + } + + @Test + public void cancelMaintenanceCmdMsHostNotInMaintenanceState() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Up); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost); + CancelMaintenanceCmd cmd = mock(CancelMaintenanceCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + + Assert.assertThrows(CloudRuntimeException.class, () -> { + spy.cancelMaintenance(cmd); + }); + } + + @Test + public void cancelMaintenanceCmd() { + ManagementServerHostVO msHost = mock(ManagementServerHostVO.class); + Mockito.when(msHost.getState()).thenReturn(ManagementServerHost.State.Maintenance); + Mockito.when(msHostDao.findById(1L)).thenReturn(msHost); + CancelMaintenanceCmd cmd = mock(CancelMaintenanceCmd.class); + Mockito.when(cmd.getManagementServerId()).thenReturn(1L); + Mockito.when(clusterManagerMock.execute(anyString(), anyLong(), anyString(), anyBoolean())).thenReturn("Success"); + + spy.cancelMaintenance(cmd); + Mockito.verify(clusterManagerMock, Mockito.times(1)).execute(anyString(), anyLong(), anyString(), anyBoolean()); + } } diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java index c4bf3e60d82..5d88acaa411 100644 --- a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java +++ b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java @@ -189,13 +189,6 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements super(); } - private Double findRatioValue(final String value) { - if (value != null) { - return Double.valueOf(value); - } - return 1.0; - } - private void updateHostMetrics(final HostMetrics hostMetrics, final HostJoinVO host) { hostMetrics.addCpuAllocated(host.getCpuReservedCapacity() + host.getCpuUsedCapacity()); hostMetrics.addMemoryAllocated(host.getMemReservedCapacity() + host.getMemUsedCapacity()); @@ -767,14 +760,10 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements if (AllowListMetricsComputation.value()) { List> cpuList = new ArrayList<>(); List> memoryList = new ArrayList<>(); - for (final Host host : hostDao.findByClusterId(clusterId)) { - if (host == null || host.getType() != Host.Type.Routing) { - continue; - } - updateHostMetrics(hostMetrics, hostJoinDao.findById(host.getId())); - HostJoinVO hostJoin = hostJoinDao.findById(host.getId()); - cpuList.add(new Ternary<>(hostJoin.getCpuUsedCapacity(), hostJoin.getCpuReservedCapacity(), hostJoin.getCpus() * hostJoin.getSpeed())); - memoryList.add(new Ternary<>(hostJoin.getMemUsedCapacity(), hostJoin.getMemReservedCapacity(), hostJoin.getTotalMemory())); + for (final HostJoinVO host : hostJoinDao.findByClusterId(clusterId, Host.Type.Routing)) { + updateHostMetrics(hostMetrics, host); + cpuList.add(new Ternary<>(host.getCpuUsedCapacity(), host.getCpuReservedCapacity(), host.getCpus() * host.getSpeed())); + memoryList.add(new Ternary<>(host.getMemUsedCapacity(), host.getMemReservedCapacity(), host.getTotalMemory())); } try { Double imbalance = ClusterDrsAlgorithm.getClusterImbalance(clusterId, cpuList, memoryList, null); @@ -955,11 +944,8 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements if (cluster == null) { continue; } - for (final Host host: hostDao.findByClusterId(cluster.getId())) { - if (host == null || host.getType() != Host.Type.Routing) { - continue; - } - updateHostMetrics(hostMetrics, hostJoinDao.findById(host.getId())); + for (final HostJoinVO host: hostJoinDao.findByClusterId(cluster.getId(), Host.Type.Routing)) { + updateHostMetrics(hostMetrics, host); } } } else { diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java b/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java index d96f5b14f0d..83c6f3dc7d4 100644 --- a/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java +++ b/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java @@ -31,11 +31,11 @@ public class ManagementServerMetricsResponse extends ManagementServerResponse { private Integer availableProcessors; @SerializedName(MetricConstants.LAST_AGENTS) - @Param(description = "the last agents this Management Server is responsible for, before preparing for maintenance", since = "4.18.1") + @Param(description = "the last agents this Management Server is responsible for, before shutdown or preparing for maintenance", since = "4.21.0.0") private List lastAgents; @SerializedName(MetricConstants.AGENTS) - @Param(description = "the agents this Management Server is responsible for", since = "4.18.1") + @Param(description = "the agents this Management Server is responsible for", since = "4.21.0.0") private List agents; @SerializedName(MetricConstants.AGENT_COUNT) diff --git a/plugins/storage/volume/adaptive/README.md b/plugins/storage/volume/adaptive/README.md index 2e3e9666866..f018f01cd5b 100644 --- a/plugins/storage/volume/adaptive/README.md +++ b/plugins/storage/volume/adaptive/README.md @@ -34,7 +34,7 @@ name=storage-volume- parent=storage ``` ### Spring Bean Context Configuration -This provides instructions of which provider implementation class to load when the Spring bean initilization is running. +This provides instructions of which provider implementation class to load when the Spring bean initialization is running. ``` storagePools = client.listStoragePools(); for (org.apache.cloudstack.storage.datastore.api.StoragePool pool : storagePools) { if (pool.getName().equals(storagePoolName)) { - logger.info("Found PowerFlex storage pool: " + storagePoolName); + logger.info("Found PowerFlex storage pool: {}", storagePoolName); final org.apache.cloudstack.storage.datastore.api.StoragePoolStatistics poolStatistics = client.getStoragePoolStatistics(pool.getId()); pool.setStatistics(poolStatistics); @@ -164,7 +159,7 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy throw new CloudRuntimeException("Cluster Id must also be specified when the Pod Id is specified for Cluster-wide primary storage."); } - URI uri = null; + URI uri; try { uri = new URI(UriUtils.encodeURIComponent(url)); if (uri.getScheme() == null || !uri.getScheme().equalsIgnoreCase("powerflex")) { @@ -174,12 +169,8 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy throw new InvalidParameterValueException(url + " is not a valid uri"); } - String storagePoolName = null; - try { - storagePoolName = URLDecoder.decode(uri.getPath(), "UTF-8"); - } catch (UnsupportedEncodingException e) { - logger.error("[ignored] we are on a platform not supporting \"UTF-8\"!?!", e); - } + String storagePoolName; + storagePoolName = URLDecoder.decode(uri.getPath(), StringUtils.getPreferredCharset()); if (storagePoolName == null) { // if decoding fails, use getPath() anyway storagePoolName = uri.getPath(); } @@ -187,7 +178,7 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy final String storageHost = uri.getHost(); final int port = uri.getPort(); - String gatewayApiURL = null; + String gatewayApiURL; if (port == -1) { gatewayApiURL = String.format("https://%s/api", storageHost); } else { @@ -321,37 +312,11 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy @Override public boolean deleteDataStore(DataStore dataStore) { - StoragePool storagePool = (StoragePool)dataStore; - StoragePoolVO storagePoolVO = primaryDataStoreDao.findById(storagePool.getId()); - if (storagePoolVO == null) { - return false; + if (cleanupDatastore(dataStore)) { + ScaleIOGatewayClientConnectionPool.getInstance().removeClient(dataStore); + return dataStoreHelper.deletePrimaryDataStore(dataStore); } - - List unusedTemplatesInPool = templateMgr.getUnusedTemplatesInPool(storagePoolVO); - for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) { - if (templatePoolVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { - templateMgr.evictTemplateFromStoragePool(templatePoolVO); - } - } - - List poolHostVOs = storagePoolHostDao.listByPoolId(dataStore.getId()); - for (StoragePoolHostVO poolHostVO : poolHostVOs) { - DeleteStoragePoolCommand deleteStoragePoolCommand = new DeleteStoragePoolCommand(storagePool); - final Answer answer = agentMgr.easySend(poolHostVO.getHostId(), deleteStoragePoolCommand); - if (answer != null && answer.getResult()) { - logger.info("Successfully deleted storage pool: {} from host: {}", storagePool, poolHostVO.getHostId()); - } else { - if (answer != null) { - logger.error("Failed to delete storage pool: {} from host: {} , result: {}", storagePool, poolHostVO.getHostId(), answer.getResult()); - } else { - logger.error("Failed to delete storage pool: {} from host: {}", storagePool, poolHostVO.getHostId()); - } - } - } - - ScaleIOGatewayClientConnectionPool.getInstance().removeClient(dataStore); - - return dataStoreHelper.deletePrimaryDataStore(dataStore); + return false; } @Override diff --git a/plugins/storage/volume/storpool/README.md b/plugins/storage/volume/storpool/README.md index a02896c42cd..a9cf3442b20 100644 --- a/plugins/storage/volume/storpool/README.md +++ b/plugins/storage/volume/storpool/README.md @@ -39,7 +39,7 @@ independent parts: * ./src/com/... directory tree: agent related classes and commands send from management to agent * ./src/org/... directory tree: management related classes -The plugin is intended to be self contained and non-intrusive, thus ideally deploying it would consist of only +The plugin is intended to be self-contained and non-intrusive, thus ideally deploying it would consist of only dropping the jar file into the appropriate places. This is the reason why all StorPool related communication (ex. data copying, volume resize) is done with StorPool specific commands even when there is a CloudStack command that does pretty much the same. @@ -183,7 +183,7 @@ This storage tag may be used later, when defining service or disk offerings. takeSnapshot + copyAsync (S => S) - Create volume from snapshoot + Create volume from snapshot create volume from snapshot management + agent(?) copyAsync (S => V) @@ -279,7 +279,7 @@ In this case only snapshots won't be downloaded to secondary storage. #### If bypass option is enabled -The snapshot exists only on PRIMARY (StorPool) storage. From this snapshot it will be created a template on SECONADRY. +The snapshot exists only on PRIMARY (StorPool) storage. From this snapshot it will be created a template on SECONDARY. #### If bypass option is disabled @@ -290,7 +290,7 @@ This is independent of StorPool as snapshots exist on secondary. ### Creating ROOT volume from templates When creating the first volume based on the given template, if snapshot of the template does not exists on StorPool it will be first downloaded (cached) to PRIMARY storage. -This is mapped to a StorPool snapshot so, creating succecutive volumes from the same template does not incur additional +This is mapped to a StorPool snapshot so, creating successive volumes from the same template does not incur additional copying of data to PRIMARY storage. This cached snapshot is garbage collected when the original template is deleted from CloudStack. This cleanup is done diff --git a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/StorPoolDownloadVolumeCommandWrapper.java b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/StorPoolDownloadVolumeCommandWrapper.java index 37284b597d2..1679e646e18 100644 --- a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/StorPoolDownloadVolumeCommandWrapper.java +++ b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/StorPoolDownloadVolumeCommandWrapper.java @@ -114,11 +114,7 @@ public final class StorPoolDownloadVolumeCommandWrapper extends CommandWrapperUTF-8 UTF-8 https://download.cloudstack.org/systemvm - 4.20.0.0 + 4.20.1.0 apache https://sonarcloud.io diff --git a/python/lib/cloudutils/syscfg.py b/python/lib/cloudutils/syscfg.py index fe68b02dfe8..78cd58bfbd4 100755 --- a/python/lib/cloudutils/syscfg.py +++ b/python/lib/cloudutils/syscfg.py @@ -39,11 +39,11 @@ class sysConfigAgentFactory: return sysConfigAgentUbuntu(glbEnv) elif distribution == "CentOS" or distribution == "RHEL5": return sysConfigEL5(glbEnv) - elif distribution == "Fedora" or distribution == "RHEL6": + elif distribution == "RHEL6": return sysConfigEL6(glbEnv) elif distribution == "RHEL7": return sysConfigEL7(glbEnv) - elif distribution in ["RHEL8", "RHEL9"]: + elif distribution in ["Fedora", "RHEL8", "RHEL9", "RHEL10"]: return sysConfigEL(glbEnv) elif distribution == "SUSE": return sysConfigSUSE(glbEnv) @@ -183,9 +183,10 @@ class sysConfigEL5(sysConfigAgentRedhatBase): networkConfigRedhat(self), libvirtConfigRedhat(self), firewallConfigAgent(self), + nfsConfig(self), cloudAgentConfig(self)] -#it covers RHEL6/Fedora13/Fedora14 +#it covers RHEL6 class sysConfigEL6(sysConfigAgentRedhatBase): def __init__(self, glbEnv): super(sysConfigEL6, self).__init__(glbEnv) diff --git a/python/lib/cloudutils/utilities.py b/python/lib/cloudutils/utilities.py index 5b07ff1eff6..ce50516193e 100755 --- a/python/lib/cloudutils/utilities.py +++ b/python/lib/cloudutils/utilities.py @@ -124,6 +124,10 @@ class Distribution: version.find("Red Hat Enterprise Linux release 9") != -1 or version.find("Linux release 9.") != -1 or version.find("Linux release 9") != -1): self.distro = "RHEL9" + elif (version.find("Red Hat Enterprise Linux Server release 10") != -1 or version.find("Scientific Linux release 10") != -1 or + version.find("Red Hat Enterprise Linux release 10") != -1 or version.find("Linux release 10.") != -1 or + version.find("Linux release 10") != -1): + self.distro = "RHEL10" elif version.find("CentOS") != -1: self.distro = "CentOS" else: diff --git a/scripts/storage/secondary/setup-sysvm-tmplt b/scripts/storage/secondary/setup-sysvm-tmplt index 8b656621891..06f0586fe34 100755 --- a/scripts/storage/secondary/setup-sysvm-tmplt +++ b/scripts/storage/secondary/setup-sysvm-tmplt @@ -99,7 +99,7 @@ if [[ -f $destdir/template.properties ]]; then failed 2 "Data already exists at destination $destdir" fi -destfiles=$(find $destdir -name \*.$ext) +destfiles=$(sudo find $destdir -name \*.$ext) if [[ "$destfiles" != "" ]]; then failed 2 "Data already exists at destination $destdir" fi @@ -108,12 +108,12 @@ tmpfolder=/tmp/cloud/templates/ mkdir -p $tmpfolder tmplfile=$tmpfolder/$localfile -sudo touch $tmplfile +touch $tmplfile if [[ $? -ne 0 ]]; then failed 2 "Failed to create temporary file in directory $tmpfolder -- is it read-only or full?\n" fi -destcap=$(df -P $destdir | awk '{print $4}' | tail -1 ) +destcap=$(sudo df -P $destdir | awk '{print $4}' | tail -1 ) [ $destcap -lt $DISKSPACE ] && echo "Insufficient free disk space for target folder $destdir: avail=${destcap}k req=${DISKSPACE}k" && failed 4 localcap=$(df -P $tmpfolder | awk '{print $4}' | tail -1 ) @@ -146,9 +146,9 @@ fi tmpltfile=$destdir/$localfile -tmpltsize=$(ls -l $tmpltfile | awk -F" " '{print $5}') +tmpltsize=$(sudo ls -l $tmpltfile | awk -F" " '{print $5}') if [[ "$ext" == "qcow2" ]]; then - vrtmpltsize=$($qemuimgcmd info $tmpltfile | grep -i 'virtual size' | sed -ne 's/.*(\([0-9]*\).*/\1/p' | xargs) + vrtmpltsize=$(sudo $qemuimgcmd info $tmpltfile | grep -i 'virtual size' | sed -ne 's/.*(\([0-9]*\).*/\1/p' | xargs) else vrtmpltsize=$tmpltsize fi diff --git a/server/conf/cloudstack-sudoers.in b/server/conf/cloudstack-sudoers.in index 5c879f3303f..710241022f5 100644 --- a/server/conf/cloudstack-sudoers.in +++ b/server/conf/cloudstack-sudoers.in @@ -18,7 +18,7 @@ # The CloudStack management server needs sudo permissions # without a password. -Cmnd_Alias CLOUDSTACK = /bin/mkdir, /bin/mount, /bin/umount, /bin/cp, /bin/chmod, /usr/bin/keytool, /bin/keytool, /bin/touch +Cmnd_Alias CLOUDSTACK = /bin/mkdir, /bin/mount, /bin/umount, /bin/cp, /bin/chmod, /usr/bin/keytool, /bin/keytool, /bin/touch, /bin/find, /bin/df, /bin/ls, /bin/qemu-img Defaults:@MSUSER@ !requiretty diff --git a/server/src/main/java/com/cloud/api/ApiDispatcher.java b/server/src/main/java/com/cloud/api/ApiDispatcher.java index 6a43ff10f31..90cbb6afc8e 100644 --- a/server/src/main/java/com/cloud/api/ApiDispatcher.java +++ b/server/src/main/java/com/cloud/api/ApiDispatcher.java @@ -94,7 +94,7 @@ public class ApiDispatcher { if (asyncJobManager.isAsyncJobsEnabled()) { asyncCreationDispatchChain.dispatch(new DispatchTask(cmd, params)); } else { - throw new CloudRuntimeException("Maintenance or Shutdown has been initiated on this management server. Can not accept new jobs"); + throw new CloudRuntimeException("Maintenance or Shutdown has been initiated on this management server. Can not accept new async creation jobs"); } } diff --git a/server/src/main/java/com/cloud/api/ApiServer.java b/server/src/main/java/com/cloud/api/ApiServer.java index 8964001a5d0..df72a2719c2 100644 --- a/server/src/main/java/com/cloud/api/ApiServer.java +++ b/server/src/main/java/com/cloud/api/ApiServer.java @@ -750,6 +750,11 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer // BaseAsyncCreateCmd: cmd params are processed and create() is called, then same workflow as BaseAsyncCmd. // BaseAsyncCmd: cmd is processed and submitted as an AsyncJob, job related info is serialized and returned. if (cmdObj instanceof BaseAsyncCmd) { + if (!asyncMgr.isAsyncJobsEnabled()) { + String msg = "Maintenance or Shutdown has been initiated on this management server. Can not accept new jobs"; + logger.warn(msg); + throw new ServerApiException(ApiErrorCode.SERVICE_UNAVAILABLE, msg); + } Long objectId = null; String objectUuid = null; if (cmdObj instanceof BaseAsyncCreateCmd) { 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 8eebb55dce9..35da341e13a 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -165,6 +165,7 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -1305,6 +1306,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q Long storageId = null; StoragePoolVO pool = null; Long userId = cmd.getUserId(); + Long userdataId = cmd.getUserdataId(); Map tags = cmd.getTags(); boolean isAdmin = false; @@ -1377,6 +1379,10 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q userVmSearchBuilder.and("templateId", userVmSearchBuilder.entity().getTemplateId(), Op.EQ); } + if (userdataId != null) { + userVmSearchBuilder.and("userdataId", userVmSearchBuilder.entity().getUserDataId(), Op.EQ); + } + if (hypervisor != null) { userVmSearchBuilder.and("hypervisorType", userVmSearchBuilder.entity().getHypervisorType(), Op.EQ); } @@ -1569,6 +1575,10 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q userVmSearchCriteria.setParameters("templateId", templateId); } + if (userdataId != null) { + userVmSearchCriteria.setParameters("userdataId", userdataId); + } + if (display != null) { userVmSearchCriteria.setParameters("display", display); } @@ -3149,28 +3159,41 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q List poolResponses = ViewResponseHelper.createStoragePoolResponse(getCustomStats, storagePools.first().toArray(new StoragePoolJoinVO[storagePools.first().size()])); Map poolUuidToIdMap = storagePools.first().stream().collect(Collectors.toMap(StoragePoolJoinVO::getUuid, StoragePoolJoinVO::getId, (a, b) -> a)); for (StoragePoolResponse poolResponse : poolResponses) { + Long poolId = poolUuidToIdMap.get(poolResponse.getId()); DataStore store = dataStoreManager.getPrimaryDataStore(poolResponse.getId()); + if (store != null) { - DataStoreDriver driver = store.getDriver(); - if (driver != null && driver.getCapabilities() != null) { - Map caps = driver.getCapabilities(); - if (Storage.StoragePoolType.NetworkFilesystem.toString().equals(poolResponse.getType()) && - HypervisorType.VMware.toString().equals(poolResponse.getHypervisor())) { - StoragePoolDetailVO detail = _storagePoolDetailsDao.findDetail(poolUuidToIdMap.get(poolResponse.getId()), Storage.Capability.HARDWARE_ACCELERATION.toString()); - if (detail != null) { - caps.put(Storage.Capability.HARDWARE_ACCELERATION.toString(), detail.getValue()); - } - } - poolResponse.setCaps(caps); - } + addPoolDetailsAndCapabilities(poolResponse, store, poolId); } - setPoolResponseNFSMountOptions(poolResponse, poolUuidToIdMap.get(poolResponse.getId())); + + setPoolResponseNFSMountOptions(poolResponse, poolId); } response.setResponses(poolResponses, storagePools.second()); return response; } + private void addPoolDetailsAndCapabilities(StoragePoolResponse poolResponse, DataStore store, Long poolId) { + Map details = _storagePoolDetailsDao.listDetailsKeyPairs(store.getId(), true); + poolResponse.setDetails(details); + + DataStoreDriver driver = store.getDriver(); + if (ObjectUtils.anyNull(driver, driver.getCapabilities())) { + return; + } + + Map caps = driver.getCapabilities(); + if (Storage.StoragePoolType.NetworkFilesystem.toString().equals(poolResponse.getType()) && HypervisorType.VMware.toString().equals(poolResponse.getHypervisor())) { + StoragePoolDetailVO detail = _storagePoolDetailsDao.findDetail(poolId, Storage.Capability.HARDWARE_ACCELERATION.toString()); + if (detail != null) { + caps.put(Storage.Capability.HARDWARE_ACCELERATION.toString(), detail.getValue()); + } + } + poolResponse.setCaps(caps); + } + + + private Pair, Integer> searchForStoragePoolsInternal(ListStoragePoolsCmd cmd) { ScopeType scopeType = ScopeType.validateAndGetScopeType(cmd.getScope()); StoragePoolStatus status = StoragePoolStatus.validateAndGetStatus(cmd.getStatus()); @@ -5441,7 +5464,11 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q mgmtResponse.addPeer(createPeerManagementServerNodeResponse(peer)); } } - mgmtResponse.setAgentsCount((long) hostDao.countByMs(mgmt.getMsid())); + List lastAgents = hostDao.listByLastMs(mgmt.getMsid()); + mgmtResponse.setLastAgents(lastAgents); + List agents = hostDao.listByMs(mgmt.getMsid()); + mgmtResponse.setAgents(agents); + mgmtResponse.setAgentsCount((long) agents.size()); mgmtResponse.setPendingJobsCount(jobManager.countPendingNonPseudoJobs(mgmt.getMsid())); mgmtResponse.setIpAddress(mgmt.getServiceIP()); mgmtResponse.setObjectName("managementserver"); diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index f33a6c2f632..7072fe6aa9a 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -446,7 +446,9 @@ public class NetworkHelperImpl implements NetworkHelper { final int retryIndex = 5; final ExcludeList[] avoids = new ExcludeList[5]; avoids[0] = new ExcludeList(); - avoids[0].addPod(routerToBeAvoid.getPodIdToDeployIn()); + if (routerToBeAvoid.getPodIdToDeployIn() != null) { + avoids[0].addPod(routerToBeAvoid.getPodIdToDeployIn()); + } avoids[1] = new ExcludeList(); avoids[1].addCluster(_hostDao.findById(routerToBeAvoid.getHostId()).getClusterId()); avoids[2] = new ExcludeList(); diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index fe056d01c10..f72644259e4 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -60,9 +60,10 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.identity.ManagementServerNode; + import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.ObjectUtils; -import org.apache.commons.lang3.StringUtils; + import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; @@ -92,7 +93,6 @@ import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; import com.cloud.cluster.ClusterManager; import com.cloud.configuration.Config; -import com.cloud.configuration.ConfigurationManager; import com.cloud.cpu.CPU; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsVO; @@ -125,7 +125,6 @@ import com.cloud.exception.DiscoveryException; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceInUseException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageConflictException; import com.cloud.exception.StorageUnavailableException; @@ -170,7 +169,6 @@ import com.cloud.storage.StorageService; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; -import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.VMTemplateDao; @@ -203,6 +201,7 @@ import com.cloud.utils.net.NetUtils; import com.cloud.utils.ssh.SSHCmdHelper; import com.cloud.utils.ssh.SshException; import com.cloud.vm.UserVmManager; +import com.cloud.utils.StringUtils; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; @@ -236,8 +235,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, @Inject private CapacityDao _capacityDao; @Inject - private DiskOfferingDao diskOfferingDao; - @Inject private ServiceOfferingDao serviceOfferingDao; @Inject private HostDao _hostDao; @@ -296,8 +293,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, @Inject private VMTemplateDao _templateDao; @Inject - private ConfigurationManager _configMgr; - @Inject private ClusterVSMMapDao _clusterVSMMapDao; @Inject private UserVmDetailsDao userVmDetailsDao; @@ -312,9 +307,9 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, private final long _nodeId = ManagementServerNode.getManagementServerId(); - private final HashMap _resourceStateAdapters = new HashMap(); + private final HashMap _resourceStateAdapters = new HashMap<>(); - private final HashMap> _lifeCycleListeners = new HashMap>(); + private final HashMap> _lifeCycleListeners = new HashMap<>(); private HypervisorType _defaultSystemVMHypervisor; private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 30; // seconds @@ -324,11 +319,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, private SearchBuilder _gpuAvailability; private void insertListener(final Integer event, final ResourceListener listener) { - List lst = _lifeCycleListeners.get(event); - if (lst == null) { - lst = new ArrayList(); - _lifeCycleListeners.put(event, lst); - } + List lst = _lifeCycleListeners.computeIfAbsent(event, k -> new ArrayList<>()); if (lst.contains(listener)) { throw new CloudRuntimeException("Duplicate resource lisener:" + listener.getClass().getSimpleName()); @@ -370,9 +361,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, @Override public void unregisterResourceEvent(final ResourceListener listener) { synchronized (_lifeCycleListeners) { - final Iterator it = _lifeCycleListeners.entrySet().iterator(); - while (it.hasNext()) { - final Map.Entry> items = (Map.Entry>)it.next(); + for (Map.Entry> items : _lifeCycleListeners.entrySet()) { final List lst = items.getValue(); lst.remove(listener); } @@ -381,7 +370,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, protected void processResourceEvent(final Integer event, final Object... params) { final List lst = _lifeCycleListeners.get(event); - if (lst == null || lst.size() == 0) { + if (lst == null || lst.isEmpty()) { return; } @@ -422,7 +411,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, @DB @Override - public List discoverCluster(final AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException, ResourceInUseException { + public List discoverCluster(final AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException { final long dcId = cmd.getZoneId(); final long podId = cmd.getPodId(); final String clusterName = cmd.getClusterName(); @@ -432,10 +421,10 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, CPU.CPUArch arch = cmd.getArch(); if (url != null) { - url = URLDecoder.decode(url); + url = URLDecoder.decode(url, com.cloud.utils.StringUtils.getPreferredCharset()); } - URI uri = null; + URI uri; // Check if the zone exists in the system final DataCenterVO zone = _dcDao.findById(dcId); @@ -519,7 +508,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, discoverer.putParam(allParams); } - final List result = new ArrayList(); + final List result = new ArrayList<>(); ClusterVO cluster = new ClusterVO(dcId, podId, clusterName); cluster.setHypervisorType(hypervisorType.toString()); @@ -540,7 +529,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, result.add(cluster); if (clusterType == Cluster.ClusterType.CloudManaged) { - final Map details = new HashMap(); + final Map details = new HashMap<>(); // should do this nicer perhaps ? if (hypervisorType == HypervisorType.Ovm3) { final Map allParams = cmd.getFullUrlParams(); @@ -578,8 +567,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, throw new InvalidParameterValueException(url + " is not a valid uri"); } - final List hosts = new ArrayList(); - Map> resources = null; + final List hosts = new ArrayList<>(); + Map> resources; resources = discoverer.find(dcId, podId, cluster.getId(), uri, username, password, null); if (resources != null) { @@ -670,7 +659,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, private List discoverHostsFull(final Long dcId, final Long podId, Long clusterId, final String clusterName, String url, String username, String password, final String hypervisorType, final List hostTags, final Map params, final boolean deferAgentCreation) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException { - URI uri = null; + URI uri; // Check if the zone exists in the system final DataCenterVO zone = _dcDao.findById(dcId); @@ -810,7 +799,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, throw new InvalidParameterValueException(url + " is not a valid uri"); } - final List hosts = new ArrayList(); + final List hosts = new ArrayList<>(); logger.info("Trying to add a new host at {} in data center {}", url, zone); boolean isHypervisorTypeSupported = false; for (final Discoverer discoverer : _discoverers) { @@ -872,7 +861,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, return null; } - HostVO host = null; + HostVO host; if (deferAgentCreation) { host = (HostVO)createHostAndAgentDeferred(resource, entry.getValue(), true, hostTags, false); } else { @@ -1099,7 +1088,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, // don't allow to remove the cluster if it has non-removed storage // pools final List storagePools = _storagePoolDao.listPoolsByCluster(cmd.getId()); - if (storagePools.size() > 0) { + if (!storagePools.isEmpty()) { logger.debug("{} still has storage pools, can't remove", cluster); throw new CloudRuntimeException(String.format("Cluster: %s cannot be removed. Cluster still has storage pools", cluster)); } @@ -1166,7 +1155,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } } - Cluster.ClusterType newClusterType = null; + Cluster.ClusterType newClusterType; if (clusterType != null && !clusterType.isEmpty()) { try { newClusterType = Cluster.ClusterType.valueOf(clusterType); @@ -1182,7 +1171,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } } - Grouping.AllocationState newAllocationState = null; + Grouping.AllocationState newAllocationState; if (allocationState != null && !allocationState.isEmpty()) { try { newAllocationState = Grouping.AllocationState.valueOf(allocationState); @@ -1244,12 +1233,13 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } } final int retry = 40; - boolean lsuccess = true; + boolean lsuccess; for (int i = 0; i < retry; i++) { lsuccess = true; try { - Thread.sleep(5 * 1000); - } catch (final Exception e) { + Thread.currentThread().wait(5 * 1000); + } catch (final InterruptedException e) { + logger.debug("thread unexpectedly interrupted during wait, while updating cluster"); } hosts = listAllUpAndEnabledHosts(Host.Type.Routing, cluster.getId(), cluster.getPodId(), cluster.getDataCenterId()); for (final HostVO host : hosts) { @@ -1258,12 +1248,12 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, break; } } - if (lsuccess == true) { + if (lsuccess) { success = true; break; } } - if (success == false) { + if (!success) { throw new CloudRuntimeException("PrepareUnmanaged Failed due to some hosts are still in UP status after 5 Minutes, please try later "); } } finally { @@ -1384,7 +1374,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, /* TODO: move below to listener */ if (host.getType() == Host.Type.Routing) { - if (vms.size() == 0) { + if (vms.isEmpty()) { return true; } @@ -1412,7 +1402,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, String logMessage = String.format( "Unsupported host.maintenance.local.storage.strategy: %s. Please set a strategy according to the global settings description: " + "'Error', 'Migration', or 'ForceStop'.", - HOST_MAINTENANCE_LOCAL_STRATEGY.value().toString()); + HOST_MAINTENANCE_LOCAL_STRATEGY.value()); logger.error(logMessage); throw new CloudRuntimeException("There are active VMs using the host's local storage pool. Please stop all VMs on this host that use local storage."); } @@ -1469,14 +1459,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, ServiceOfferingVO offeringVO = serviceOfferingDao.findById(vm.getServiceOfferingId()); final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offeringVO, null, null); plan.setMigrationPlan(true); - DeployDestination dest = null; - DeploymentPlanner.ExcludeList avoids = new DeploymentPlanner.ExcludeList(); - avoids.addHost(host.getId()); - try { - dest = deploymentManager.planDeployment(profile, plan, avoids, null); - } catch (InsufficientServerCapacityException e) { - throw new CloudRuntimeException(String.format("Maintenance failed, could not find deployment destination for VM: %s.", vm), e); - } + DeployDestination dest = getDeployDestination(vm, profile, plan, host); Host destHost = dest.getHost(); try { @@ -1487,6 +1470,22 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } } + private DeployDestination getDeployDestination(VMInstanceVO vm, VirtualMachineProfile profile, DataCenterDeployment plan, HostVO hostToAvoid) { + DeployDestination dest; + DeploymentPlanner.ExcludeList avoids = new DeploymentPlanner.ExcludeList(); + avoids.addHost(hostToAvoid.getId()); + try { + dest = deploymentManager.planDeployment(profile, plan, avoids, null); + } catch (InsufficientServerCapacityException e) { + throw new CloudRuntimeException(String.format("Maintenance failed, could not find deployment destination for VM [id=%s, name=%s].", vm.getId(), vm.getInstanceName()), + e); + } + if (dest == null) { + throw new CloudRuntimeException(String.format("Maintenance failed, could not find deployment destination for VM [id=%s, name=%s], using plan: %s.", vm.getId(), vm.getInstanceName(), plan)); + } + return dest; + } + @Override public boolean maintain(final long hostId) throws AgentUnavailableException { final Boolean result = propagateResourceEvent(hostId, ResourceState.Event.AdminAskMaintenance); @@ -1535,15 +1534,15 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, List migratingInVMs = _vmDao.findByHostInStates(hostId, State.Migrating); - if (migratingInVMs.size() > 0) { + if (!migratingInVMs.isEmpty()) { throw new CloudRuntimeException("Host contains incoming VMs migrating. Please wait for them to complete before putting to maintenance."); } - if (_vmDao.findByHostInStates(hostId, State.Starting, State.Stopping).size() > 0) { + if (!_vmDao.findByHostInStates(hostId, State.Starting, State.Stopping).isEmpty()) { throw new CloudRuntimeException("Host contains VMs in starting/stopping state. Please wait for them to complete before putting to maintenance."); } - if (_vmDao.findByHostInStates(hostId, State.Error, State.Unknown).size() > 0) { + if (!_vmDao.findByHostInStates(hostId, State.Error, State.Unknown).isEmpty()) { throw new CloudRuntimeException("Host contains VMs in error/unknown/shutdown state. Please fix errors to proceed."); } @@ -1564,25 +1563,22 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, if(StringUtils.isBlank(HOST_MAINTENANCE_LOCAL_STRATEGY.value())) { return false; } - return HOST_MAINTENANCE_LOCAL_STRATEGY.value().toLowerCase().equals(WorkType.Migration.toString().toLowerCase()); + return HOST_MAINTENANCE_LOCAL_STRATEGY.value().equalsIgnoreCase(WorkType.Migration.toString()); } protected boolean isMaintenanceLocalStrategyForceStop() { if(StringUtils.isBlank(HOST_MAINTENANCE_LOCAL_STRATEGY.value())) { return false; } - return HOST_MAINTENANCE_LOCAL_STRATEGY.value().toLowerCase().equals(WorkType.ForceStop.toString().toLowerCase()); + return HOST_MAINTENANCE_LOCAL_STRATEGY.value().equalsIgnoreCase(WorkType.ForceStop.toString()); } /** * Returns true if the host.maintenance.local.storage.strategy is the Default: "Error", blank, empty, or null. */ protected boolean isMaintenanceLocalStrategyDefault() { - if (StringUtils.isBlank(HOST_MAINTENANCE_LOCAL_STRATEGY.value().toString()) - || HOST_MAINTENANCE_LOCAL_STRATEGY.value().toLowerCase().equals(State.Error.toString().toLowerCase())) { - return true; - } - return false; + return StringUtils.isBlank(HOST_MAINTENANCE_LOCAL_STRATEGY.value()) + || HOST_MAINTENANCE_LOCAL_STRATEGY.value().equalsIgnoreCase(State.Error.toString()); } /** @@ -1733,7 +1729,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, * Return true if host goes into Maintenance mode. There are various possibilities for VMs' states * on a host. We need to track the various VM states on each run and accordingly transit to the * appropriate state. - * * We change states as follows - * 1. If there are no VMs in running, migrating, starting, stopping, error, unknown states we can move * to maintenance state. Note that there cannot be incoming migrations as the API Call prepare for @@ -1907,7 +1902,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, guestOSDetail.setValue(String.valueOf(guestOSCategory.getId())); _hostDetailsDao.update(guestOSDetail.getId(), guestOSDetail); } else { - final Map detail = new HashMap(); + final Map detail = new HashMap<>(); detail.put("guest.os.category.id", String.valueOf(guestOSCategory.getId())); _hostDetailsDao.persist(hostId, detail); } @@ -2057,9 +2052,9 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, @Override public List getSupportedHypervisorTypes(final long zoneId, final boolean forVirtualRouter, final Long podId) { - final List hypervisorTypes = new ArrayList(); + final List hypervisorTypes = new ArrayList<>(); - List clustersForZone = new ArrayList(); + List clustersForZone; if (podId != null) { clustersForZone = _clusterDao.listByPodId(podId); } else { @@ -2068,7 +2063,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, for (final ClusterVO cluster : clustersForZone) { final HypervisorType hType = cluster.getHypervisorType(); - if (!forVirtualRouter || forVirtualRouter && hType != HypervisorType.BareMetal && hType != HypervisorType.Ovm) { + if (!forVirtualRouter || (hType != HypervisorType.BareMetal && hType != HypervisorType.Ovm)) { hypervisorTypes.add(hType); } } @@ -2104,7 +2099,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, if (isValid) { final List clusters = _clusterDao.listByDcHyType(zoneId, defaultHyper.toString()); - if (clusters.size() <= 0) { + if (clusters.isEmpty()) { isValid = false; } } @@ -2121,7 +2116,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, HypervisorType defaultHype = getDefaultHypervisor(zoneId); if (defaultHype == HypervisorType.None) { final List supportedHypes = getSupportedHypervisorTypes(zoneId, false, null); - if (supportedHypes.size() > 0) { + if (!supportedHypes.isEmpty()) { Collections.shuffle(supportedHypes); defaultHype = supportedHypes.get(0); } @@ -2245,10 +2240,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, final String cidrNetmask = NetUtils.getCidrSubNet("255.255.255.255", cidrSize); final long cidrNetmaskNumeric = NetUtils.ip2Long(cidrNetmask); final long serverNetmaskNumeric = NetUtils.ip2Long(serverPrivateNetmask); - if (serverNetmaskNumeric > cidrNetmaskNumeric) { - return false; - } - return true; + return serverNetmaskNumeric <= cidrNetmaskNumeric; } private HostVO getNewHost(StartupCommand[] startupCommands) { @@ -2262,11 +2254,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, host = findHostByGuid(startupCommand.getGuidWithoutResource()); - if (host != null) { - return host; - } - - return null; + return host; // even when host == null! } protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource resource, final Map details, List hostTags, @@ -2297,11 +2285,11 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } } - long dcId = -1; + long dcId; DataCenterVO dc = _dcDao.findByName(dataCenter); if (dc == null) { try { - dcId = Long.parseLong(dataCenter); + dcId = Long.parseLong(dataCenter != null ? dataCenter : "-1"); dc = _dcDao.findById(dcId); } catch (final NumberFormatException e) { logger.debug("Cannot parse " + dataCenter + " into Long."); @@ -2315,7 +2303,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, HostPodVO p = _podDao.findByName(pod, dcId); if (p == null) { try { - final long podId = Long.parseLong(pod); + final long podId = Long.parseLong(pod != null ? pod : "-1"); p = _podDao.findById(podId); } catch (final NumberFormatException e) { logger.debug("Cannot parse " + pod + " into Long."); @@ -2334,9 +2322,9 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, clusterId = Long.valueOf(cluster); } catch (final NumberFormatException e) { if (podId != null) { - ClusterVO c = _clusterDao.findBy(cluster, podId.longValue()); + ClusterVO c = _clusterDao.findBy(cluster, podId); if (c == null) { - c = new ClusterVO(dcId, podId.longValue(), cluster); + c = new ClusterVO(dcId, podId, cluster); c = _clusterDao.persist(c); } clusterId = c.getId(); @@ -2439,7 +2427,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, for (Long hostId : hostIds) { DetailVO hostDetailVO = _hostDetailsDao.findDetail(hostId, name); - if (hostDetailVO == null || Boolean.parseBoolean(hostDetailVO.getValue()) == false) { + if (hostDetailVO == null || !Boolean.parseBoolean(hostDetailVO.getValue())) { clusterSupportsResigning = false; break; @@ -2531,7 +2519,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } if (logger.isDebugEnabled()) { - new Request(-1l, -1l, cmds, true, false).logD("Startup request from directly connected host: ", true); + new Request(-1L, -1L, cmds, true, false).logD("Startup request from directly connected host: ", true); } if (old) { @@ -2601,7 +2589,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } if (logger.isDebugEnabled()) { - new Request(-1l, -1l, cmds, true, false).logD("Startup request from directly connected host: ", true); + new Request(-1L, -1L, cmds, true, false).logD("Startup request from directly connected host: ", true); } if (old) { @@ -2702,8 +2690,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, throw new InvalidParameterValueException("Can't find zone with id " + zoneId); } - final Map details = hostDetails; - final String guid = details.get("guid"); + final String guid = hostDetails.get("guid"); final List currentHosts = listAllUpAndEnabledHostsInOneZoneByType(hostType, zoneId); for (final HostVO currentHost : currentHosts) { if (currentHost.getGuid().equals(guid)) { @@ -2719,7 +2706,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, return createHostVO(cmds, null, null, null, ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_CONNECTED); } - private void checkIPConflicts(final HostPodVO pod, final DataCenterVO dc, final String serverPrivateIP, final String serverPrivateNetmask, final String serverPublicIP, final String serverPublicNetmask) { + private void checkIPConflicts(final HostPodVO pod, final DataCenterVO dc, final String serverPrivateIP, final String serverPublicIP) { // If the server's private IP is the same as is public IP, this host has // a host-only private network. Don't check for conflicts with the // private IP address table. @@ -2748,7 +2735,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, // If the server's public IP address is already in the database, // return false final List existingPublicIPs = _publicIPAddressDao.listByDcIdIpAddress(dc.getId(), serverPublicIP); - if (existingPublicIPs.size() > 0) { + if (!existingPublicIPs.isEmpty()) { throw new IllegalArgumentException("The public ip address of the server (" + serverPublicIP + ") is already in use in zone: " + dc.getName()); } } @@ -2785,7 +2772,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, final HostPodVO pod = _podDao.findById(host.getPodId()); final DataCenterVO dc = _dcDao.findById(host.getDataCenterId()); - checkIPConflicts(pod, dc, ssCmd.getPrivateIpAddress(), ssCmd.getPublicIpAddress(), ssCmd.getPublicIpAddress(), ssCmd.getPublicNetmask()); + checkIPConflicts(pod, dc, ssCmd.getPrivateIpAddress(), ssCmd.getPublicIpAddress()); host.setType(com.cloud.host.Host.Type.Routing); host.setDetails(details); host.setCaps(ssCmd.getCapabilities()); @@ -2823,8 +2810,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, throw new UnableDeleteHostException("Failed to set primary storage into maintenance mode"); } } catch (final Exception e) { - logger.debug("Failed to set primary storage into maintenance mode, due to: " + e.toString()); - throw new UnableDeleteHostException("Failed to set primary storage into maintenance mode, due to: " + e.toString()); + logger.debug("Failed to set primary storage into maintenance mode", e); + throw new UnableDeleteHostException("Failed to set primary storage into maintenance mode, due to: " + e); } } @@ -2968,7 +2955,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, if (result.getReturnCode() != 0) { throw new CloudRuntimeException(String.format("Could not restart agent on %s due to: %s", host, result.getStdErr())); } - logger.debug("cloudstack-agent restart result: " + result.toString()); + logger.debug("cloudstack-agent restart result: {}", result); } catch (final SshException e) { throw new CloudRuntimeException("SSH to agent is enabled, but agent restart failed", e); } @@ -2989,7 +2976,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, } @Override - public boolean executeUserRequest(final long hostId, final ResourceState.Event event) throws AgentUnavailableException { + public boolean executeUserRequest(final long hostId, final ResourceState.Event event) { if (event == ResourceState.Event.AdminAskMaintenance) { return doMaintain(hostId); } else if (event == ResourceState.Event.AdminCancelMaintenance) { @@ -3315,7 +3302,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, public HostStats getHostStatistics(final Host host) { final Answer answer = _agentMgr.easySend(host.getId(), new GetHostStatsCommand(host.getGuid(), host.getName(), host.getId())); - if (answer != null && answer instanceof UnsupportedAnswer) { + if (answer instanceof UnsupportedAnswer) { return null; } @@ -3351,20 +3338,16 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, @Override public String getHostTags(final long hostId) { final List hostTags = _hostTagsDao.getHostTags(hostId).parallelStream().map(HostTagVO::getTag).collect(Collectors.toList()); - if (hostTags == null) { - return null; - } else { - return com.cloud.utils.StringUtils.listToCsvTags(hostTags); - } + return StringUtils.listToCsvTags(hostTags); } @Override public List listByDataCenter(final long dcId) { final List pods = _podDao.listByDataCenterId(dcId); - final ArrayList pcs = new ArrayList(); + final ArrayList pcs = new ArrayList<>(); for (final HostPodVO pod : pods) { final List clusters = _clusterDao.listByPodId(pod.getId()); - if (clusters.size() == 0) { + if (clusters.isEmpty()) { pcs.add(new PodCluster(pod, null)); } else { for (final ClusterVO cluster : clusters) { @@ -3409,7 +3392,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, public boolean isHostGpuEnabled(final long hostId) { final SearchCriteria sc = _gpuAvailability.create(); sc.setParameters("hostId", hostId); - return _hostGpuGroupsDao.customSearch(sc, null).size() > 0 ? true : false; + return !_hostGpuGroupsDao.customSearch(sc, null).isEmpty(); } @Override @@ -3474,7 +3457,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, // Update GPU group capacity final TransactionLegacy txn = TransactionLegacy.currentTxn(); txn.start(); - _hostGpuGroupsDao.persist(hostId, new ArrayList(groupDetails.keySet())); + _hostGpuGroupsDao.persist(hostId, new ArrayList<>(groupDetails.keySet())); _vgpuTypesDao.persist(hostId, groupDetails); txn.commit(); } @@ -3482,7 +3465,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, @Override public HashMap> getGPUStatistics(final HostVO host) { final Answer answer = _agentMgr.easySend(host.getId(), new GetGPUStatsCommand(host.getGuid(), host.getName())); - if (answer != null && answer instanceof UnsupportedAnswer) { + if (answer instanceof UnsupportedAnswer) { return null; } if (answer == null || !answer.getResult()) { @@ -3523,7 +3506,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, @ActionEvent(eventType = EventTypes.EVENT_HOST_RESERVATION_RELEASE, eventDescription = "releasing host reservation", async = true) public boolean releaseHostReservation(final Long hostId) { try { - return Transaction.execute(new TransactionCallback() { + return Transaction.execute(new TransactionCallback<>() { @Override public Boolean doInTransaction(final TransactionStatus status) { final PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId); diff --git a/server/src/main/java/com/cloud/server/StatsCollector.java b/server/src/main/java/com/cloud/server/StatsCollector.java index cbd175eece2..e82d99028d7 100644 --- a/server/src/main/java/com/cloud/server/StatsCollector.java +++ b/server/src/main/java/com/cloud/server/StatsCollector.java @@ -752,21 +752,21 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc logger.debug(String.format("%s is running...", this.getClass().getSimpleName())); long msid = ManagementServerNode.getManagementServerId(); ManagementServerHostVO mshost = null; - ManagementServerHostStatsEntry hostStatsEntry = null; + ManagementServerHostStatsEntry msHostStatsEntry = null; try { mshost = managementServerHostDao.findByMsid(msid); // get local data - hostStatsEntry = getDataFrom(mshost); - managementServerHostStats.put(mshost.getUuid(), hostStatsEntry); + msHostStatsEntry = getDataFrom(mshost); + managementServerHostStats.put(mshost.getUuid(), msHostStatsEntry); // send to other hosts - clusterManager.publishStatus(gson.toJson(hostStatsEntry)); + clusterManager.publishStatus(gson.toJson(msHostStatsEntry)); } catch (Throwable t) { // pokemon catch to make sure the thread stays running logger.error("Error trying to retrieve management server host statistics", t); } try { // send to DB - storeStatus(hostStatsEntry, mshost); + storeStatus(msHostStatsEntry, mshost); } catch (Throwable t) { // pokemon catch to make sure the thread stays running logger.error("Error trying to store management server host statistics", t); @@ -834,11 +834,11 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc } private void getDataBaseStatistics(ManagementServerHostStatsEntry newEntry, long msid) { - newEntry.setLastAgents(_agentMgr.getLastAgents()); + List lastAgents = _hostDao.listByLastMs(msid); + newEntry.setLastAgents(lastAgents); List agents = _hostDao.listByMs(msid); newEntry.setAgents(agents); - int count = _hostDao.countByMs(msid); - newEntry.setAgentCount(count); + newEntry.setAgentCount(agents.size()); } private void getMemoryData(@NotNull ManagementServerHostStatsEntry newEntry) { diff --git a/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java b/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java index 1f0f439d819..3336d44dba8 100644 --- a/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java @@ -19,10 +19,13 @@ package org.apache.cloudstack.agent.lb; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.EnumSet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.naming.ConfigurationException; @@ -33,6 +36,8 @@ import org.apache.cloudstack.agent.lb.algorithm.IndirectAgentLBStaticAlgorithm; import org.apache.cloudstack.config.ApiServiceConfiguration; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import com.cloud.agent.AgentManager; @@ -40,6 +45,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.MigrateAgentConnectionCommand; import com.cloud.cluster.ManagementServerHostVO; import com.cloud.cluster.dao.ManagementServerHostDao; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; @@ -49,20 +55,20 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; import com.cloud.resource.ResourceState; import com.cloud.utils.component.ComponentLifecycleBase; +import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.exception.CloudRuntimeException; -import org.apache.commons.collections.CollectionUtils; - public class IndirectAgentLBServiceImpl extends ComponentLifecycleBase implements IndirectAgentLB, Configurable { public static final ConfigKey IndirectAgentLBAlgorithm = new ConfigKey<>(String.class, "indirect.agent.lb.algorithm", "Advanced", "static", - "The algorithm to be applied on the provided 'host' management server list that is sent to indirect agents. Allowed values are: static, roundrobin and shuffle.", + "The algorithm to be applied on the provided management server list in the 'host' config that that is sent to indirect agents. Allowed values are: static, roundrobin and shuffle.", true, ConfigKey.Scope.Global, null, null, null, null, null, ConfigKey.Kind.Select, "static,roundrobin,shuffle"); public static final ConfigKey IndirectAgentLBCheckInterval = new ConfigKey<>("Advanced", Long.class, "indirect.agent.lb.check.interval", "0", - "The interval in seconds after which agent should check and try to connect to its preferred host. Set 0 to disable it.", + "The interval in seconds after which indirect agent should check and try to connect to its preferred host (the first management server from the propagated list provided in the 'host' config)." + + " Set 0 to disable it.", true, ConfigKey.Scope.Cluster); private static Map algorithmMap = new HashMap<>(); @@ -85,6 +91,8 @@ public class IndirectAgentLBServiceImpl extends ComponentLifecycleBase implement ResourceState.ErrorInMaintenance, ResourceState.PrepareForMaintenance); private static final List agentValidHostTypes = List.of(Host.Type.Routing, Host.Type.ConsoleProxy, Host.Type.SecondaryStorage, Host.Type.SecondaryStorageVM); + private static final List agentNonRoutingHostTypes = List.of(Host.Type.ConsoleProxy, + Host.Type.SecondaryStorage, Host.Type.SecondaryStorageVM); private static final List agentValidHypervisorTypes = List.of( Hypervisor.HypervisorType.KVM, Hypervisor.HypervisorType.LXC); @@ -246,8 +254,18 @@ public class IndirectAgentLBServiceImpl extends ComponentLifecycleBase implement agentBasedHosts.add(host); } + private List getAllAgentBasedNonRoutingHostsFromDB(final Long zoneId, final Long msId) { + return hostDao.findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(zoneId, null, msId, + agentValidResourceStates, agentNonRoutingHostTypes, agentValidHypervisorTypes); + } + + private List getAllAgentBasedRoutingHostsFromDB(final Long zoneId, final Long clusterId, final Long msId) { + return hostDao.findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(zoneId, clusterId, msId, + agentValidResourceStates, List.of(Host.Type.Routing), agentValidHypervisorTypes); + } + private List getAllAgentBasedHostsFromDB(final Long zoneId, final Long clusterId) { - return hostDao.findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(zoneId, clusterId, + return hostDao.findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(zoneId, clusterId, null, agentValidResourceStates, agentValidHostTypes, agentValidHypervisorTypes); } @@ -287,31 +305,159 @@ public class IndirectAgentLBServiceImpl extends ComponentLifecycleBase implement @Override public void propagateMSListToAgents() { logger.debug("Propagating management server list update to agents"); + ExecutorService setupMSListExecutorService = Executors.newFixedThreadPool(10, new NamedThreadFactory("SetupMSList-Worker")); final String lbAlgorithm = getLBAlgorithmName(); + final Long globalLbCheckInterval = getLBPreferredHostCheckInterval(null); List zones = dataCenterDao.listAll(); for (DataCenterVO zone : zones) { List zoneHostIds = new ArrayList<>(); + List nonRoutingHostIds = getAllAgentBasedNonRoutingHostsFromDB(zone.getId(), null); + zoneHostIds.addAll(nonRoutingHostIds); Map> clusterHostIdsMap = new HashMap<>(); List clusterIds = clusterDao.listAllClusterIds(zone.getId()); for (Long clusterId : clusterIds) { - List hostIds = getAllAgentBasedHostsFromDB(zone.getId(), clusterId); + List hostIds = getAllAgentBasedRoutingHostsFromDB(zone.getId(), clusterId, null); clusterHostIdsMap.put(clusterId, hostIds); zoneHostIds.addAll(hostIds); } zoneHostIds.sort(Comparator.comparingLong(x -> x)); + final List avoidMsList = mshostDao.listNonUpStateMsIPs(); + for (Long nonRoutingHostId : nonRoutingHostIds) { + setupMSListExecutorService.submit(new SetupMSListTask(nonRoutingHostId, zone.getId(), zoneHostIds, avoidMsList, lbAlgorithm, globalLbCheckInterval)); + } for (Long clusterId : clusterIds) { - final Long lbCheckInterval = getLBPreferredHostCheckInterval(clusterId); + final Long clusterLbCheckInterval = getLBPreferredHostCheckInterval(clusterId); List hostIds = clusterHostIdsMap.get(clusterId); for (Long hostId : hostIds) { - final List msList = getManagementServerList(hostId, zone.getId(), zoneHostIds); - final SetupMSListCommand cmd = new SetupMSListCommand(msList, lbAlgorithm, lbCheckInterval); - final Answer answer = agentManager.easySend(hostId, cmd); - if (answer == null || !answer.getResult()) { - logger.warn("Failed to setup management servers list to the agent of ID: {}", hostId); - } + setupMSListExecutorService.submit(new SetupMSListTask(hostId, zone.getId(), zoneHostIds, avoidMsList, lbAlgorithm, clusterLbCheckInterval)); } } } + + setupMSListExecutorService.shutdown(); + try { + if (!setupMSListExecutorService.awaitTermination(300, TimeUnit.SECONDS)) { + setupMSListExecutorService.shutdownNow(); + } + } catch (InterruptedException e) { + setupMSListExecutorService.shutdownNow(); + logger.debug(String.format("Force shutdown setup ms list service as it did not shutdown in the desired time due to: %s", e.getMessage())); + } + } + + private final class SetupMSListTask extends ManagedContextRunnable { + private Long hostId; + private Long dcId; + private List orderedHostIdList; + private List avoidMsList; + private String lbAlgorithm; + private Long lbCheckInterval; + + public SetupMSListTask(Long hostId, Long dcId, List orderedHostIdList, List avoidMsList, + String lbAlgorithm, Long lbCheckInterval) { + this.hostId = hostId; + this.dcId = dcId; + this.orderedHostIdList = orderedHostIdList; + this.avoidMsList = avoidMsList; + this.lbAlgorithm = lbAlgorithm; + this.lbCheckInterval = lbCheckInterval; + } + + @Override + protected void runInContext() { + final List msList = getManagementServerList(hostId, dcId, orderedHostIdList); + final SetupMSListCommand cmd = new SetupMSListCommand(msList, avoidMsList, lbAlgorithm, lbCheckInterval); + cmd.setWait(60); + final Answer answer = agentManager.easySend(hostId, cmd); + if (answer == null || !answer.getResult()) { + logger.warn(String.format("Failed to setup management servers list to the agent of ID: %d", hostId)); + } + } + } + + protected boolean migrateNonRoutingHostAgentsInZone(String fromMsUuid, long fromMsId, DataCenter dc, + long migrationStartTimeInMs, long timeoutDurationInMs, final List avoidMsList, String lbAlgorithm, + boolean lbAlgorithmChanged, List orderedHostIdList) { + List systemVmAgentsInDc = getAllAgentBasedNonRoutingHostsFromDB(dc.getId(), fromMsId); + if (CollectionUtils.isEmpty(systemVmAgentsInDc)) { + return true; + } + logger.debug(String.format("Migrating %d non-routing host agents from management server node %d (id: %s) of zone %s", + systemVmAgentsInDc.size(), fromMsId, fromMsUuid, dc)); + ExecutorService migrateAgentsExecutorService = Executors.newFixedThreadPool(5, new NamedThreadFactory("MigrateNonRoutingHostAgent-Worker")); + Long lbCheckInterval = getLBPreferredHostCheckInterval(null); + boolean stopMigration = false; + for (final Long hostId : systemVmAgentsInDc) { + long migrationElapsedTimeInMs = System.currentTimeMillis() - migrationStartTimeInMs; + if (migrationElapsedTimeInMs >= timeoutDurationInMs) { + logger.debug(String.format("Stop migrating remaining non-routing host agents from management server node %d (id: %s), timed out", fromMsId, fromMsUuid)); + stopMigration = true; + break; + } + + migrateAgentsExecutorService.submit(new MigrateAgentConnectionTask(fromMsId, hostId, dc.getId(), orderedHostIdList, avoidMsList, lbCheckInterval, lbAlgorithm, lbAlgorithmChanged)); + } + + if (stopMigration) { + migrateAgentsExecutorService.shutdownNow(); + return false; + } + + migrateAgentsExecutorService.shutdown(); + long pendingTimeoutDurationInMs = timeoutDurationInMs - (System.currentTimeMillis() - migrationStartTimeInMs); + try { + if (pendingTimeoutDurationInMs <= 0 || !migrateAgentsExecutorService.awaitTermination(pendingTimeoutDurationInMs, TimeUnit.MILLISECONDS)) { + migrateAgentsExecutorService.shutdownNow(); + } + } catch (InterruptedException e) { + migrateAgentsExecutorService.shutdownNow(); + logger.debug(String.format("Force shutdown migrate non-routing agents service as it did not shutdown in the desired time due to: %s", e.getMessage())); + } + + return true; + } + + protected boolean migrateRoutingHostAgentsInCluster(long clusterId, String fromMsUuid, long fromMsId, DataCenter dc, + long migrationStartTimeInMs, long timeoutDurationInMs, final List avoidMsList, String lbAlgorithm, + boolean lbAlgorithmChanged, List orderedHostIdList) { + + List agentBasedHostsOfMsInDcAndCluster = getAllAgentBasedRoutingHostsFromDB(dc.getId(), clusterId, fromMsId); + if (CollectionUtils.isEmpty(agentBasedHostsOfMsInDcAndCluster)) { + return true; + } + logger.debug(String.format("Migrating %d indirect routing host agents from management server node %d (id: %s) of zone %s, " + + "cluster ID: %d", agentBasedHostsOfMsInDcAndCluster.size(), fromMsId, fromMsUuid, dc, clusterId)); + ExecutorService migrateAgentsExecutorService = Executors.newFixedThreadPool(10, new NamedThreadFactory("MigrateRoutingHostAgent-Worker")); + Long lbCheckInterval = getLBPreferredHostCheckInterval(clusterId); + boolean stopMigration = false; + for (final Long hostId : agentBasedHostsOfMsInDcAndCluster) { + long migrationElapsedTimeInMs = System.currentTimeMillis() - migrationStartTimeInMs; + if (migrationElapsedTimeInMs >= timeoutDurationInMs) { + logger.debug(String.format("Stop migrating remaining indirect routing host agents from management server node %d (id: %s), timed out", fromMsId, fromMsUuid)); + stopMigration = true; + break; + } + + migrateAgentsExecutorService.submit(new MigrateAgentConnectionTask(fromMsId, hostId, dc.getId(), orderedHostIdList, avoidMsList, lbCheckInterval, lbAlgorithm, lbAlgorithmChanged)); + } + + if (stopMigration) { + migrateAgentsExecutorService.shutdownNow(); + return false; + } + + migrateAgentsExecutorService.shutdown(); + long pendingTimeoutDurationInMs = timeoutDurationInMs - (System.currentTimeMillis() - migrationStartTimeInMs); + try { + if (pendingTimeoutDurationInMs <= 0 || !migrateAgentsExecutorService.awaitTermination(pendingTimeoutDurationInMs, TimeUnit.MILLISECONDS)) { + migrateAgentsExecutorService.shutdownNow(); + } + } catch (InterruptedException e) { + migrateAgentsExecutorService.shutdownNow(); + logger.debug(String.format("Force shutdown migrate routing agents service as it did not shutdown in the desired time due to: %s", e.getMessage())); + } + + return true; } @Override @@ -322,7 +468,7 @@ public class IndirectAgentLBServiceImpl extends ComponentLifecycleBase implement } logger.debug(String.format("Migrating indirect agents from management server node %d (id: %s) to other nodes", fromMsId, fromMsUuid)); - long migrationStartTime = System.currentTimeMillis(); + long migrationStartTimeInMs = System.currentTimeMillis(); if (!haveAgentBasedHosts(fromMsId)) { logger.info(String.format("No indirect agents available on management server node %d (id: %s), to migrate", fromMsId, fromMsUuid)); return true; @@ -342,37 +488,75 @@ public class IndirectAgentLBServiceImpl extends ComponentLifecycleBase implement List dataCenterList = dcDao.listAll(); for (DataCenterVO dc : dataCenterList) { - Long dcId = dc.getId(); - List orderedHostIdList = getOrderedHostIdList(dcId); - List agentBasedHostsOfMsInDc = getAllAgentBasedHostsInDc(fromMsId, dcId); - if (CollectionUtils.isEmpty(agentBasedHostsOfMsInDc)) { - continue; - } - logger.debug(String.format("Migrating %d indirect agents from management server node %d (id: %s) of zone %s", agentBasedHostsOfMsInDc.size(), fromMsId, fromMsUuid, dc)); - for (final Host host : agentBasedHostsOfMsInDc) { - long migrationElapsedTimeInMs = System.currentTimeMillis() - migrationStartTime; - if (migrationElapsedTimeInMs >= timeoutDurationInMs) { - logger.debug(String.format("Stop migrating remaining indirect agents from management server node %d (id: %s), timed out", fromMsId, fromMsUuid)); - return false; - } - - List msList = null; - Long lbCheckInterval = 0L; - if (lbAlgorithmChanged) { - // send new MS list when there is change in lb algorithm - msList = getManagementServerList(host.getId(), dcId, orderedHostIdList, lbAlgorithm); - lbCheckInterval = getLBPreferredHostCheckInterval(host.getClusterId()); - } - - final MigrateAgentConnectionCommand cmd = new MigrateAgentConnectionCommand(msList, avoidMsList, lbAlgorithm, lbCheckInterval); - agentManager.easySend(host.getId(), cmd); //answer not received as the agent disconnects and reconnects to other ms - updateLastManagementServer(host.getId(), fromMsId); + if (!migrateAgentsInZone(dc, fromMsUuid, fromMsId, avoidMsList, lbAlgorithm, lbAlgorithmChanged, + migrationStartTimeInMs, timeoutDurationInMs)) { + return false; } } return true; } + private boolean migrateAgentsInZone(DataCenterVO dc, String fromMsUuid, long fromMsId, List avoidMsList, + String lbAlgorithm, boolean lbAlgorithmChanged, long migrationStartTimeInMs, long timeoutDurationInMs) { + List orderedHostIdList = getOrderedHostIdList(dc.getId()); + if (!migrateNonRoutingHostAgentsInZone(fromMsUuid, fromMsId, dc, migrationStartTimeInMs, + timeoutDurationInMs, avoidMsList, lbAlgorithm, lbAlgorithmChanged, orderedHostIdList)) { + return false; + } + List clusterIds = clusterDao.listAllClusterIds(dc.getId()); + for (Long clusterId : clusterIds) { + if (!migrateRoutingHostAgentsInCluster(clusterId, fromMsUuid, fromMsId, dc, migrationStartTimeInMs, + timeoutDurationInMs, avoidMsList, lbAlgorithm, lbAlgorithmChanged, orderedHostIdList)) { + return false; + } + } + return true; + } + + private final class MigrateAgentConnectionTask extends ManagedContextRunnable { + private long fromMsId; + Long hostId; + Long dcId; + List orderedHostIdList; + List avoidMsList; + Long lbCheckInterval; + String lbAlgorithm; + boolean lbAlgorithmChanged; + + public MigrateAgentConnectionTask(long fromMsId, Long hostId, Long dcId, List orderedHostIdList, + List avoidMsList, Long lbCheckInterval, String lbAlgorithm, boolean lbAlgorithmChanged) { + this.fromMsId = fromMsId; + this.hostId = hostId; + this.orderedHostIdList = orderedHostIdList; + this.avoidMsList = avoidMsList; + this.lbCheckInterval = lbCheckInterval; + this.lbAlgorithm = lbAlgorithm; + this.lbAlgorithmChanged = lbAlgorithmChanged; + } + + @Override + protected void runInContext() { + try { + List msList = null; + if (lbAlgorithmChanged) { + // send new MS list when there is change in lb algorithm + msList = getManagementServerList(hostId, dcId, orderedHostIdList, lbAlgorithm); + } + + final MigrateAgentConnectionCommand cmd = new MigrateAgentConnectionCommand(msList, avoidMsList, lbAlgorithm, lbCheckInterval); + cmd.setWait(60); + final Answer answer = agentManager.easySend(hostId, cmd); //may not receive answer when the agent disconnects immediately and try reconnecting to other ms host + if (answer != null && !answer.getResult()) { + logger.warn(String.format("Error while initiating migration of agent connection for host agent ID: %d - %s", hostId, answer.getDetails())); + } + updateLastManagementServer(hostId, fromMsId); + } catch (final Exception e) { + logger.error(String.format("Error migrating agent connection for host %d", hostId), e); + } + } + } + private void updateLastManagementServer(long hostId, long msId) { HostVO hostVO = hostDao.findById(hostId); if (hostVO != null) { diff --git a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java index d2732eca98d..68b6a2ad047 100644 --- a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java @@ -394,10 +394,10 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { boolean result = false; try { - vm.setBackupOfferingId(null); - vm.setBackupExternalId(null); - vm.setBackupVolumes(null); result = backupProvider.removeVMFromBackupOffering(vm); + vm.setBackupOfferingId(null); + vm.setBackupVolumes(null); + vm.setBackupExternalId(null); if (result && backupProvider.willDeleteBackupsOnOfferingRemoval()) { final List backups = backupDao.listByVmId(null, vm.getId()); for (final Backup backup : backups) { diff --git a/server/src/main/java/org/apache/cloudstack/storage/heuristics/presetvariables/Domain.java b/server/src/main/java/org/apache/cloudstack/storage/heuristics/presetvariables/Domain.java index 6565c06bfbb..704cbf4373e 100644 --- a/server/src/main/java/org/apache/cloudstack/storage/heuristics/presetvariables/Domain.java +++ b/server/src/main/java/org/apache/cloudstack/storage/heuristics/presetvariables/Domain.java @@ -16,7 +16,7 @@ // under the License. package org.apache.cloudstack.storage.heuristics.presetvariables; -public class Domain extends GenericHeuristicPresetVariable{ +public class Domain extends GenericHeuristicPresetVariable { private String id; public String getId() { diff --git a/server/src/main/java/org/apache/cloudstack/storage/heuristics/presetvariables/GenericHeuristicPresetVariable.java b/server/src/main/java/org/apache/cloudstack/storage/heuristics/presetvariables/GenericHeuristicPresetVariable.java index 28d4327954e..b85b7763eee 100644 --- a/server/src/main/java/org/apache/cloudstack/storage/heuristics/presetvariables/GenericHeuristicPresetVariable.java +++ b/server/src/main/java/org/apache/cloudstack/storage/heuristics/presetvariables/GenericHeuristicPresetVariable.java @@ -36,10 +36,12 @@ public class GenericHeuristicPresetVariable { fieldNamesToIncludeInToString.add("name"); } + /*** + * Converts the preset variable into a valid JSON object that will be injected into the JS interpreter. + * This method should not be overridden or changed. + */ @Override - public String toString() { - return String.format("GenericHeuristicPresetVariable %s", - ReflectionToStringBuilderUtils.reflectOnlySelectedFields( - this, fieldNamesToIncludeInToString.toArray(new String[0]))); + public final String toString() { + return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, fieldNamesToIncludeInToString.toArray(new String[0])); } } diff --git a/server/src/test/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImplTest.java b/server/src/test/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImplTest.java index 0c0097393ca..1b9923ad3ea 100644 --- a/server/src/test/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImplTest.java +++ b/server/src/test/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImplTest.java @@ -106,7 +106,7 @@ public class IndirectAgentLBServiceImplTest { List hostIds = hosts.stream().map(HostVO::getId).collect(Collectors.toList()); doReturn(hostIds).when(hostDao).findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(Mockito.anyLong(), - Mockito.eq(null), Mockito.anyList(), Mockito.anyList(), Mockito.anyList()); + Mockito.eq(null), Mockito.eq(null), Mockito.anyList(), Mockito.anyList(), Mockito.anyList()); } @Before @@ -203,14 +203,14 @@ public class IndirectAgentLBServiceImplTest { @Test public void testGetOrderedRunningHostIdsEmptyList() { doReturn(Collections.emptyList()).when(hostDao).findHostIdsByZoneClusterResourceStateTypeAndHypervisorType( - Mockito.eq(DC_1_ID), Mockito.eq(null), Mockito.anyList(), Mockito.anyList(), Mockito.anyList()); + Mockito.eq(DC_1_ID), Mockito.eq(null), Mockito.eq(null), Mockito.anyList(), Mockito.anyList(), Mockito.anyList()); Assert.assertTrue(agentMSLB.getOrderedHostIdList(DC_1_ID).isEmpty()); } @Test public void testGetOrderedRunningHostIdsOrderList() { doReturn(Arrays.asList(host4.getId(), host2.getId(), host1.getId(), host3.getId())).when(hostDao) - .findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(Mockito.eq(DC_1_ID), Mockito.eq(null), + .findHostIdsByZoneClusterResourceStateTypeAndHypervisorType(Mockito.eq(DC_1_ID), Mockito.eq(null), Mockito.eq(null), Mockito.anyList(), Mockito.anyList(), Mockito.anyList()); Assert.assertEquals(Arrays.asList(host1.getId(), host2.getId(), host3.getId(), host4.getId()), agentMSLB.getOrderedHostIdList(DC_1_ID)); diff --git a/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/AccountTest.java b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/AccountTest.java new file mode 100644 index 00000000000..f7610438b78 --- /dev/null +++ b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/AccountTest.java @@ -0,0 +1,46 @@ +// 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. + +package org.apache.cloudstack.storage.heuristics.presetvariables; + +import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class AccountTest { + + @Test + public void toStringTestReturnsValidJson() { + Account variable = new Account(); + variable.setName("test name"); + variable.setId("test id"); + + Domain domainVariable = new Domain(); + domainVariable.setId("domain id"); + domainVariable.setName("domain name"); + variable.setDomain(domainVariable); + + String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "id", "domain"); + String result = variable.toString(); + + Assert.assertEquals(expected, result); + } + +} diff --git a/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/DomainTest.java b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/DomainTest.java new file mode 100644 index 00000000000..a1ec6854ecc --- /dev/null +++ b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/DomainTest.java @@ -0,0 +1,41 @@ +// 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. + +package org.apache.cloudstack.storage.heuristics.presetvariables; + +import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class DomainTest { + + @Test + public void toStringTestReturnsValidJson() { + Domain variable = new Domain(); + variable.setName("test name"); + variable.setId("test id"); + + String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "id"); + String result = variable.toString(); + + Assert.assertEquals(expected, result); + } + +} diff --git a/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/GenericHeuristicPresetVariableTest.java b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/GenericHeuristicPresetVariableTest.java new file mode 100644 index 00000000000..cd295e92caf --- /dev/null +++ b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/GenericHeuristicPresetVariableTest.java @@ -0,0 +1,40 @@ +// 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. + +package org.apache.cloudstack.storage.heuristics.presetvariables; + +import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class GenericHeuristicPresetVariableTest { + + @Test + public void toStringTestReturnsValidJson() { + GenericHeuristicPresetVariable variable = new GenericHeuristicPresetVariable(); + variable.setName("test name"); + + String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name"); + String result = variable.toString(); + + Assert.assertEquals(expected, result); + } + +} diff --git a/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/SecondaryStorageTest.java b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/SecondaryStorageTest.java new file mode 100644 index 00000000000..a09386789cf --- /dev/null +++ b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/SecondaryStorageTest.java @@ -0,0 +1,45 @@ +// 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. + +package org.apache.cloudstack.storage.heuristics.presetvariables; + +import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SecondaryStorageTest { + + @Test + public void toStringTestReturnsValidJson() { + SecondaryStorage variable = new SecondaryStorage(); + variable.setName("test name"); + variable.setId("test id"); + variable.setProtocol("test protocol"); + variable.setUsedDiskSize(1L); + variable.setTotalDiskSize(2L); + + String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "id", + "protocol", "usedDiskSize", "totalDiskSize"); + String result = variable.toString(); + + Assert.assertEquals(expected, result); + } + +} diff --git a/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/SnapshotTest.java b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/SnapshotTest.java new file mode 100644 index 00000000000..b8476cd8e46 --- /dev/null +++ b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/SnapshotTest.java @@ -0,0 +1,44 @@ +// 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. + +package org.apache.cloudstack.storage.heuristics.presetvariables; + +import com.cloud.hypervisor.Hypervisor; +import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SnapshotTest { + + @Test + public void toStringTestReturnsValidJson() { + Snapshot variable = new Snapshot(); + variable.setName("test name"); + variable.setSize(1L); + variable.setHypervisorType(Hypervisor.HypervisorType.KVM); + + String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "size", + "hypervisorType"); + String result = variable.toString(); + + Assert.assertEquals(expected, result); + } + +} diff --git a/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/TemplateTest.java b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/TemplateTest.java new file mode 100644 index 00000000000..2c1582befb2 --- /dev/null +++ b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/TemplateTest.java @@ -0,0 +1,46 @@ +// 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. + +package org.apache.cloudstack.storage.heuristics.presetvariables; + +import com.cloud.hypervisor.Hypervisor; +import com.cloud.storage.Storage; +import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class TemplateTest { + + @Test + public void toStringTestReturnsValidJson() { + Template variable = new Template(); + variable.setName("test name"); + variable.setTemplateType(Storage.TemplateType.USER); + variable.setHypervisorType(Hypervisor.HypervisorType.KVM); + variable.setFormat(Storage.ImageFormat.QCOW2); + + String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "templateType", + "hypervisorType", "format"); + String result = variable.toString(); + + Assert.assertEquals(expected, result); + } + +} diff --git a/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/VolumeTest.java b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/VolumeTest.java new file mode 100644 index 00000000000..e74ddc93ec5 --- /dev/null +++ b/server/src/test/java/org/apache/cloudstack/storage/heuristics/presetvariables/VolumeTest.java @@ -0,0 +1,44 @@ +// 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. + +package org.apache.cloudstack.storage.heuristics.presetvariables; + +import com.cloud.storage.Storage; +import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class VolumeTest { + + @Test + public void toStringTestReturnsValidJson() { + Volume variable = new Volume(); + variable.setName("test name"); + variable.setFormat(Storage.ImageFormat.QCOW2); + variable.setSize(1L); + + String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "format", + "size"); + String result = variable.toString(); + + Assert.assertEquals(expected, result); + } + +} diff --git a/test/integration/component/test_acl_sharednetwork_deployVM-impersonation.py b/test/integration/component/test_acl_sharednetwork_deployVM-impersonation.py index 212320c2c2f..4a12345b6e8 100644 --- a/test/integration/component/test_acl_sharednetwork_deployVM-impersonation.py +++ b/test/integration/component/test_acl_sharednetwork_deployVM-impersonation.py @@ -344,7 +344,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_all_domainuser(self): """ - Valiate that ROOT admin is able to deploy a VM for other users in a shared network with scope=all + Validate that ROOT admin is able to deploy a VM for other users in a shared network with scope=all """ # Deploy VM for a user in a domain under ROOT as admin @@ -372,7 +372,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_all_domainadminuser(self): """ - Valiate that ROOT admin is able to deploy a VM for a domain admin users in a shared network with scope=all + Validate that ROOT admin is able to deploy a VM for a domain admin users in a shared network with scope=all """ # Deploy VM for an admin user in a domain under ROOT as admin @@ -400,7 +400,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_all_subdomainuser(self): """ - Valiate that ROOT admin is able to deploy a VM for any user in a subdomain in a shared network with scope=all + Validate that ROOT admin is able to deploy a VM for any user in a subdomain in a shared network with scope=all """ # Deploy VM as user in a subdomain under ROOT @@ -426,7 +426,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_all_subdomainadminuser(self): """ - Valiate that ROOT admin is able to deploy a VM for admin user in a domain in a shared network with scope=all + Validate that ROOT admin is able to deploy a VM for admin user in a domain in a shared network with scope=all """ # Deploy VM as an admin user in a subdomain under ROOT @@ -453,7 +453,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_all_ROOTuser(self): """ - Valiate that ROOT admin is able to deploy a VM for user in ROOT domain in a shared network with scope=all + Validate that ROOT admin is able to deploy a VM for user in ROOT domain in a shared network with scope=all """ # Deploy VM as user in ROOT domain @@ -482,7 +482,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_nosubdomainaccess_domainuser(self): """ - Valiate that ROOT admin is able to deploy a VM for domain user in a shared network with scope=domain with no subdomain access + Validate that ROOT admin is able to deploy a VM for domain user in a shared network with scope=domain with no subdomain access """ # Deploy VM as user in a domain that has shared network with no subdomain access @@ -510,7 +510,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_nosubdomainaccess_domainadminuser(self): """ - Valiate that ROOT admin is able to deploy a VM for domain admin user in a shared network with scope=domain with no subdomain access + Validate that ROOT admin is able to deploy a VM for domain admin user in a shared network with scope=domain with no subdomain access """ # Deploy VM as an admin user in a domain that has shared network with no subdomain access @@ -538,7 +538,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_nosubdomainaccess_subdomainuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for sub domain user in a shared network with scope=domain with no subdomain access + Validate that ROOT admin is NOT able to deploy a VM for sub domain user in a shared network with scope=domain with no subdomain access """ # Deploy VM as user in a subdomain under a domain that has shared network with no subdomain access @@ -569,7 +569,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_nosubdomainaccess_subdomainadminuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for sub domain admin user in a shared network with scope=domain with no subdomain access + Validate that ROOT admin is NOT able to deploy a VM for sub domain admin user in a shared network with scope=domain with no subdomain access """ # Deploy VM as an admin user in a subdomain under a domain that has shared network with no subdomain access @@ -599,7 +599,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_nosubdomainaccess_parentdomainuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for parent domain user in a shared network with scope=domain with no subdomain access + Validate that ROOT admin is NOT able to deploy a VM for parent domain user in a shared network with scope=domain with no subdomain access """ # Deploy VM as user in parentdomain of a domain that has shared network with no subdomain access @@ -629,7 +629,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_nosubdomainaccess_parentdomainadminuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for parent domain admin user in a shared network with scope=domain with no subdomain access + Validate that ROOT admin is NOT able to deploy a VM for parent domain admin user in a shared network with scope=domain with no subdomain access """ # Deploy VM as an admin user in parentdomain of a domain that has shared network with no subdomain access @@ -659,7 +659,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_nosubdomainaccess_ROOTuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for parent domain admin user in a shared network with scope=domain with no subdomain access + Validate that ROOT admin is NOT able to deploy a VM for parent domain admin user in a shared network with scope=domain with no subdomain access """ # Deploy VM as user in ROOT domain @@ -691,7 +691,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_withsubdomainaccess_domainuser(self): """ - Valiate that ROOT admin is able to deploy a VM for domain user in a shared network with scope=domain with subdomain access + Validate that ROOT admin is able to deploy a VM for domain user in a shared network with scope=domain with subdomain access """ # Deploy VM as user in a domain that has shared network with subdomain access @@ -719,7 +719,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_withsubdomainaccess_domainadminuser(self): """ - Valiate that ROOT admin is able to deploy a VM for domain admin user in a shared network with scope=domain with subdomain access + Validate that ROOT admin is able to deploy a VM for domain admin user in a shared network with scope=domain with subdomain access """ # Deploy VM as an admin user in a domain that has shared network with subdomain access @@ -747,7 +747,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_withsubdomainaccess_subdomainuser(self): """ - Valiate that ROOT admin is able to deploy a VM for subdomain user in a shared network with scope=domain with subdomain access + Validate that ROOT admin is able to deploy a VM for subdomain user in a shared network with scope=domain with subdomain access """ # Deploy VM as user in a subdomain under a domain that has shared network with subdomain access @@ -774,7 +774,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_withsubdomainaccess_subdomainadminuser(self): """ - Valiate that ROOT admin is able to deploy a VM for subdomain admin user in a shared network with scope=domain with subdomain access + Validate that ROOT admin is able to deploy a VM for subdomain admin user in a shared network with scope=domain with subdomain access """ # Deploy VM as an admin user in a subdomain under a domain that has shared network with subdomain access @@ -801,7 +801,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_withsubdomainaccess_parentdomainuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for parent domain user in a shared network with scope=domain with subdomain access + Validate that ROOT admin is NOT able to deploy a VM for parent domain user in a shared network with scope=domain with subdomain access """ # Deploy VM as user in parentdomain of a domain that has shared network with subdomain access @@ -831,7 +831,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_withsubdomainaccess_parentdomainadminuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for parent domain admin user in a shared network with scope=domain with subdomain access + Validate that ROOT admin is NOT able to deploy a VM for parent domain admin user in a shared network with scope=domain with subdomain access """ # Deploy VM as an admin user in parentdomain of a domain that has shared network with subdomain access @@ -861,7 +861,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_domain_withsubdomainaccess_ROOTuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for user in ROOT domain in a shared network with scope=domain with subdomain access + Validate that ROOT admin is NOT able to deploy a VM for user in ROOT domain in a shared network with scope=domain with subdomain access """ # Deploy VM as user in ROOT domain @@ -893,7 +893,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_account_domainuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for user in the same domain but in a different account in a shared network with scope=account + Validate that ROOT admin is NOT able to deploy a VM for user in the same domain but in a different account in a shared network with scope=account """ # Deploy VM as user in a domain under the same domain but different account from the account that has a shared network with scope=account @@ -923,7 +923,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_account_domainadminuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for admin user in the same domain but in a different account in a shared network with scope=account + Validate that ROOT admin is NOT able to deploy a VM for admin user in the same domain but in a different account in a shared network with scope=account """ # Deploy VM as admin user for a domain that has an account with shared network with scope=account @@ -953,7 +953,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_account_user(self): """ - Valiate that ROOT admin is able to deploy a VM for regular user in a shared network with scope=account + Validate that ROOT admin is able to deploy a VM for regular user in a shared network with scope=account """ # Deploy VM as account with shared network with scope=account @@ -981,7 +981,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_account_differentdomain(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for a admin user in a shared network with scope=account which the admin user does not have access to + Validate that ROOT admin is NOT able to deploy a VM for a admin user in a shared network with scope=account which the admin user does not have access to """ # Deploy VM as an admin user in a subdomain under ROOT @@ -1011,7 +1011,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_admin_scope_account_ROOTuser(self): """ - Valiate that ROOT admin is NOT able to deploy a VM for a user in ROOT domain in a shared network with scope=account which the user does not have access to + Validate that ROOT admin is NOT able to deploy a VM for a user in ROOT domain in a shared network with scope=account which the user does not have access to """ # Deploy VM as user in ROOT domain @@ -1043,7 +1043,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_all_domainuser(self): """ - Valiate that Domain admin is able to deploy a VM for a domain user in a shared network with scope=all + Validate that Domain admin is able to deploy a VM for a domain user in a shared network with scope=all """ # Deploy VM for a user in a domain under ROOT as admin @@ -1070,7 +1070,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_all_domainadminuser(self): """ - Valiate that Domain admin is able to deploy a VM for a domain admin user in a shared network with scope=all + Validate that Domain admin is able to deploy a VM for a domain admin user in a shared network with scope=all """ # Deploy VM for an admin user in a domain under ROOT as admin @@ -1097,7 +1097,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_all_subdomainuser(self): """ - Valiate that Domain admin is able to deploy a VM for a sub domain user in a shared network with scope=all + Validate that Domain admin is able to deploy a VM for a sub domain user in a shared network with scope=all """ # Deploy VM as user in a subdomain under ROOT @@ -1123,7 +1123,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_all_subdomainadminuser(self): """ - Valiate that Domain admin is able to deploy a VM for a sub domain admin user in a shared network with scope=all + Validate that Domain admin is able to deploy a VM for a sub domain admin user in a shared network with scope=all """ # Deploy VM as an admin user in a subdomain under ROOT @@ -1149,7 +1149,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_all_ROOTuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for user in ROOT domain in a shared network with scope=all + Validate that Domain admin is NOT able to deploy a VM for user in ROOT domain in a shared network with scope=all """ # Deploy VM as user in ROOT domain @@ -1177,7 +1177,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_all_crossdomainuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for user in other domain in a shared network with scope=all + Validate that Domain admin is NOT able to deploy a VM for user in other domain in a shared network with scope=all """ # Deploy VM as user in ROOT domain @@ -1208,7 +1208,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_nosubdomainaccess_domainuser(self): """ - Valiate that Domain admin is able to deploy a VM for domain user in a shared network with scope=Domain and no subdomain access + Validate that Domain admin is able to deploy a VM for domain user in a shared network with scope=Domain and no subdomain access """ # Deploy VM as user in a domain that has shared network with no subdomain access @@ -1235,7 +1235,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_nosubdomainaccess_domainadminuser(self): """ - Valiate that Domain admin is able to deploy a VM for domain admin user in a shared network with scope=Domain and no subdomain access + Validate that Domain admin is able to deploy a VM for domain admin user in a shared network with scope=Domain and no subdomain access """ # Deploy VM as an admin user in a domain that has shared network with no subdomain access @@ -1263,7 +1263,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_nosubdomainaccess_subdomainuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for sub domain user in a shared network with scope=Domain and no subdomain access + Validate that Domain admin is NOT able to deploy a VM for sub domain user in a shared network with scope=Domain and no subdomain access """ # Deploy VM as user in a subdomain under a domain that has shared network with no subdomain access @@ -1293,7 +1293,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_nosubdomainaccess_subdomainadminuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for sub domain admin user in a shared network with scope=Domain and no subdomain access + Validate that Domain admin is NOT able to deploy a VM for sub domain admin user in a shared network with scope=Domain and no subdomain access """ # Deploy VM as an admin user in a subdomain under a domain that has shared network with no subdomain access @@ -1323,7 +1323,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_nosubdomainaccess_parentdomainuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for parent domain user in a shared network with scope=Domain and no subdomain access + Validate that Domain admin is NOT able to deploy a VM for parent domain user in a shared network with scope=Domain and no subdomain access """ # Deploy VM as user in parentdomain of a domain that has shared network with no subdomain access @@ -1353,7 +1353,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_nosubdomainaccess_parentdomainadminuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for parent domain admin user in a shared network with scope=Domain and no subdomain access + Validate that Domain admin is NOT able to deploy a VM for parent domain admin user in a shared network with scope=Domain and no subdomain access """ # Deploy VM as an admin user in parentdomain of a domain that has shared network with no subdomain access @@ -1383,7 +1383,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_nosubdomainaccess_ROOTuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for user in ROOT domain in a shared network with scope=Domain and no subdomain access + Validate that Domain admin is NOT able to deploy a VM for user in ROOT domain in a shared network with scope=Domain and no subdomain access """ # Deploy VM as user in ROOT domain @@ -1414,7 +1414,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_withsubdomainaccess_domainuser(self): """ - Valiate that Domain admin is able to deploy a VM for regular user in domain in a shared network with scope=Domain and subdomain access + Validate that Domain admin is able to deploy a VM for regular user in domain in a shared network with scope=Domain and subdomain access """ # Deploy VM as user in a domain that has shared network with subdomain access @@ -1441,7 +1441,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_withsubdomainaccess_domainadminuser(self): """ - Valiate that Domain admin is able to deploy a VM for admin user in domain in a shared network with scope=Domain and subdomain access + Validate that Domain admin is able to deploy a VM for admin user in domain in a shared network with scope=Domain and subdomain access """ # Deploy VM as an admin user in a domain that has shared network with subdomain access @@ -1468,7 +1468,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_withsubdomainaccess_subdomainuser(self): """ - Valiate that Domain admin is able to deploy a VM for regular user in subdomain in a shared network with scope=Domain and subdomain access + Validate that Domain admin is able to deploy a VM for regular user in subdomain in a shared network with scope=Domain and subdomain access """ # Deploy VM as user in a subdomain under a domain that has shared network with subdomain access @@ -1494,7 +1494,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_withsubdomainaccess_subdomainadminuser(self): """ - Valiate that Domain admin is able to deploy a VM for admin user in subdomain in a shared network with scope=Domain and subdomain access + Validate that Domain admin is able to deploy a VM for admin user in subdomain in a shared network with scope=Domain and subdomain access """ # Deploy VM as an admin user in a subdomain under a domain that has shared network with subdomain access @@ -1520,7 +1520,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_withsubdomainaccess_parentdomainuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for regular user in parent domain in a shared network with scope=Domain and subdomain access + Validate that Domain admin is NOT able to deploy a VM for regular user in parent domain in a shared network with scope=Domain and subdomain access """ # Deploy VM as user in parentdomain of a domain that has shared network with subdomain access @@ -1549,7 +1549,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_withsubdomainaccess_parentdomainadminuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for admin user in parent domain in a shared network with scope=Domain and subdomain access + Validate that Domain admin is NOT able to deploy a VM for admin user in parent domain in a shared network with scope=Domain and subdomain access """ # Deploy VM as an admin user in parentdomain of a domain that has shared network with subdomain access @@ -1579,7 +1579,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_domain_withsubdomainaccess_ROOTuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for user in ROOT domain in a shared network with scope=Domain and subdomain access + Validate that Domain admin is NOT able to deploy a VM for user in ROOT domain in a shared network with scope=Domain and subdomain access """ # Deploy VM as user in ROOT domain @@ -1610,7 +1610,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_account_domainuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for user in the same domain but belonging to a different account in a shared network with scope=account + Validate that Domain admin is NOT able to deploy a VM for user in the same domain but belonging to a different account in a shared network with scope=account """ # Deploy VM as user in a domain under the same domain but different account from the account that has a shared network with scope=account @@ -1639,7 +1639,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_account_domainadminuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for an admin user in the same domain but belonging to a different account in a shared network with scope=account + Validate that Domain admin is NOT able to deploy a VM for an admin user in the same domain but belonging to a different account in a shared network with scope=account """ # Deploy VM as admin user for a domain that has an account with shared network with scope=account @@ -1668,7 +1668,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_account_user(self): """ - Valiate that Domain admin is able to deploy a VM for an regular user in a shared network with scope=account + Validate that Domain admin is able to deploy a VM for an regular user in a shared network with scope=account """ # Deploy VM as account with shared network with scope=account @@ -1695,7 +1695,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_account_differentdomain(self): """ - Valiate that Domain admin is able NOT able to deploy a VM for an regular user from a differnt domain in a shared network with scope=account + Validate that Domain admin is able NOT able to deploy a VM for an regular user from a differnt domain in a shared network with scope=account """ # Deploy VM as an admin user in a subdomain under ROOT @@ -1724,7 +1724,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_domainadmin_scope_account_ROOTuser(self): """ - Valiate that Domain admin is NOT able to deploy a VM for an regular user in ROOT domain in a shared network with scope=account + Validate that Domain admin is NOT able to deploy a VM for an regular user in ROOT domain in a shared network with scope=account """ # Deploy VM as user in ROOT domain @@ -1754,7 +1754,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_regularuser_scope_all_anotherusersamedomain(self): """ - Valiate that regular user is able NOT able to deploy a VM for another user in the same domain in a shared network with scope=all + Validate that regular user is able NOT able to deploy a VM for another user in the same domain in a shared network with scope=all """ # Deploy VM for a user in a domain under ROOT as admin @@ -1782,7 +1782,7 @@ class TestSharedNetworkImpersonation(cloudstackTestCase): @attr("simulator_only", tags=["advanced"], required_hardware="false") def test_deployVM_in_sharedNetwork_as_regularuser_scope_all_crossdomain(self): """ - Valiate that regular user is able NOT able to deploy a VM for another user in a different domain in a shared network with scope=all + Validate that regular user is able NOT able to deploy a VM for another user in a different domain in a shared network with scope=all """ # Deploy VM for a user in a domain under ROOT as admin diff --git a/tools/appliance/systemvmtemplate/template-base_aarch64-target_aarch64.json b/tools/appliance/systemvmtemplate/template-base_aarch64-target_aarch64.json index e2b4d3bce92..2165b571576 100644 --- a/tools/appliance/systemvmtemplate/template-base_aarch64-target_aarch64.json +++ b/tools/appliance/systemvmtemplate/template-base_aarch64-target_aarch64.json @@ -32,8 +32,8 @@ "format": "qcow2", "headless": true, "http_directory": "http", - "iso_checksum": "sha512:04a2a128852c2dff8bb71779ad325721385051eb1264d897bdb5918ab207a9b1de636ded149c56c61a09eb8c7f428496815e70d3be31b1b1cf4c70bf6427cedd", - "iso_url": "https://cdimage.debian.org/mirror/cdimage/release/12.9.0/arm64/iso-cd/debian-12.9.0-arm64-netinst.iso", + "iso_checksum": "sha512:022895e699231c94abf7012f86cabc587dc576f07f856c87609d5d40c1f921d805a5a862cba94c1a47d09aaa565ec445222e338e73d1fa1affc4fc5908bb50ad", + "iso_url": "https://cdimage.debian.org/mirror/cdimage/release/12.10.0/arm64/iso-cd/debian-12.10.0-arm64-netinst.iso", "net_device": "virtio-net", "output_directory": "../dist", "qemu_binary": "qemu-system-aarch64", diff --git a/tools/appliance/systemvmtemplate/template-base_x86_64-target_aarch64.json b/tools/appliance/systemvmtemplate/template-base_x86_64-target_aarch64.json index b1cd7c69e2c..7f1b5c4befa 100644 --- a/tools/appliance/systemvmtemplate/template-base_x86_64-target_aarch64.json +++ b/tools/appliance/systemvmtemplate/template-base_x86_64-target_aarch64.json @@ -31,8 +31,8 @@ "format": "qcow2", "headless": true, "http_directory": "http", - "iso_checksum": "sha512:04a2a128852c2dff8bb71779ad325721385051eb1264d897bdb5918ab207a9b1de636ded149c56c61a09eb8c7f428496815e70d3be31b1b1cf4c70bf6427cedd", - "iso_url": "https://cdimage.debian.org/mirror/cdimage/release/12.9.0/arm64/iso-cd/debian-12.9.0-arm64-netinst.iso", + "iso_checksum": "sha512:022895e699231c94abf7012f86cabc587dc576f07f856c87609d5d40c1f921d805a5a862cba94c1a47d09aaa565ec445222e338e73d1fa1affc4fc5908bb50ad", + "iso_url": "https://cdimage.debian.org/mirror/cdimage/release/12.10.0/arm64/iso-cd/debian-12.10.0-arm64-netinst.iso", "net_device": "virtio-net", "output_directory": "../dist", "qemu_binary": "qemu-system-aarch64", diff --git a/tools/appliance/systemvmtemplate/template-base_x86_64-target_x86_64.json b/tools/appliance/systemvmtemplate/template-base_x86_64-target_x86_64.json index 322d1620e03..d74c408cbc3 100644 --- a/tools/appliance/systemvmtemplate/template-base_x86_64-target_x86_64.json +++ b/tools/appliance/systemvmtemplate/template-base_x86_64-target_x86_64.json @@ -27,8 +27,8 @@ "format": "qcow2", "headless": true, "http_directory": "http", - "iso_checksum": "sha512:9ebe405c3404a005ce926e483bc6c6841b405c4d85e0c8a7b1707a7fe4957c617ae44bd807a57ec3e5c2d3e99f2101dfb26ef36b3720896906bdc3aaeec4cd80", - "iso_url": "https://cdimage.debian.org/mirror/cdimage/release/12.9.0/amd64/iso-cd/debian-12.9.0-amd64-netinst.iso", + "iso_checksum": "sha512:cb089def0684fd93c9c2fbe45fd16ecc809c949a6fd0c91ee199faefe7d4b82b64658a264a13109d59f1a40ac3080be2f7bd3d8bf3e9cdf509add6d72576a79b", + "iso_url": "https://cdimage.debian.org/mirror/cdimage/release/12.10.0/amd64/iso-cd/debian-12.10.0-amd64-netinst.iso", "net_device": "virtio-net", "output_directory": "../dist", "qemuargs": [ diff --git a/tools/docker/README.md b/tools/docker/README.md index 0977b896606..024eebb2aad 100644 --- a/tools/docker/README.md +++ b/tools/docker/README.md @@ -58,7 +58,7 @@ docker run -ti --name cloudstack --link cloudstack-mysql:mysql -d -p 8080:8080 - ### Marvin Use marvin to deploy or test your CloudStack environment. -Use Marvin with cloudstack connection thru the API port (8096) +Use Marvin with cloudstack connection through the API port (8096) ``` docker pull cloudstack/marvin @@ -99,7 +99,7 @@ tag:latest = main branch docker build -f Dockerfile.centos6 -t cloudstack/management_centos6 . ``` -2. on jenkins, database and systemvm.iso are pre-deployed. the inital start require privileged container to +2. on jenkins, database and systemvm.iso are pre-deployed. the initial start require privileged container to mount systemvm.iso and copy ssh_rsa.pub into it. ``` diff --git a/tools/marvin/marvin/config/test_data.py b/tools/marvin/marvin/config/test_data.py index 3485eeb8b18..bde48c87616 100644 --- a/tools/marvin/marvin/config/test_data.py +++ b/tools/marvin/marvin/config/test_data.py @@ -1069,7 +1069,7 @@ test_data = { "format": "raw", "hypervisor": "kvm", "ostype": "Other Linux (64-bit)", - "url": "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img", + "url": "https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-amd64.img", "requireshvm": "True", "ispublic": "True", "isextractable": "False" diff --git a/tools/marvin/marvin/misc/build/CI.md b/tools/marvin/marvin/misc/build/CI.md index 390932cfd36..659ccea8558 100644 --- a/tools/marvin/marvin/misc/build/CI.md +++ b/tools/marvin/marvin/misc/build/CI.md @@ -72,7 +72,7 @@ systems - these are virtual/physical infrastructure mapped to cobbler profiles b When a new image needs to be added we create a 'distro' in cobbler and associate that with a profile's kickstart. Any new systems to be hooked-up to be serviced by the profile can then be added easily by cmd line. -b. Puppet master - Cobbler reimages machines on-demand but it is upto puppet recipes to do configuration management within them. The configuration management is required for kvm hypervisors (kvm agent for eg:) and for the cloudstack management server which needs mysql, cloudstack, etc. The puppetmasterd daemon on the driver-vm is responsible for 'kicking' nodes to initiate configuration management on themselves when they come alive. +b. Puppet master - Cobbler reimages machines on-demand, but it is upto puppet recipes to do configuration management within them. The configuration management is required for kvm hypervisors (kvm agent for eg:) and for the cloudstack management server which needs mysql, cloudstack, etc. The puppetmasterd daemon on the driver-vm is responsible for 'kicking' nodes to initiate configuration management on themselves when they come alive. So the driver-vm is also the repository of all the puppet recipes for various modules that need to be configured for the test infrastructure to work. The modules are placed in /etc/puppet and bear the same structure as our GitHub repo. When we need to affect a configuration change on any of our systems we only change the GitHub repo and the systems in place are affected upon next run. @@ -80,7 +80,7 @@ c. dnsmasq - DNS is controlled by cobbler but its configuration of hosts is set d. dhcp - DHCP is also done by dnsmasq. All configuration is in /etc/dnsmasq.conf. static mac-ip-name mappings are given for hypervisors while the virtual instances get dynamic ips -e. ipmitool - ipmi for power management is setup on all the test servers and the ipmitool provides a convienient cli for booting the machines on the network into PXEing. +e. ipmitool - ipmi for power management is setup on all the test servers and the ipmitool provides a convenient cli for booting the machines on the network into PXEing. f. jenkins-slave - jenkins slave.jar is placed on the driver-vm as a service in /etc/init.d to react to jenkins schedules and to post reports to. The slave runs in headless mode as the driver-vm does not run X. @@ -99,7 +99,7 @@ d. multi-pod tests marvin integration ================== -once cloudstack has been installed and the hypervisors prepared we are ready to use marvin to stitch together zones, pods, clusters and compute and storage to put together a 'cloud'. once configured - we perform a cursory health check to see if we have all systemVMs running in all zones and that built-in templates are downloaded in all zones. Subsequently we are able to launch tests on this environment +once cloudstack has been installed and the hypervisors prepared we are ready to use marvin to stitch together zones, pods, clusters and compute and storage to put together a 'cloud'. once configured - we perform a cursory health check to see if we have all systemVMs running in all zones and that built-in templates are downloaded in all zones. Subsequently, we are able to launch tests on this environment Only the latest tests from git are run on the setup. This allows us to test in a pseudo-continuous fashion with a nightly build deployed on the environment. Each test run takes a few hours to finish. @@ -121,7 +121,7 @@ When jenkins triggers the job following sequence of actions occur on the test in 3. we fetch the last successful marvin build from builds.a.o and install it within this virtualenv. installing a new marvin on each run helps us test with the latest APIs available. -4. we fetch the latest version of the driver script from github:cloud-autodeploy. fetching the latest allows us to make adjustments to the infra without having to copy scripts in to the test infrastrcuture. +4. we fetch the latest version of the driver script from github:cloud-autodeploy. fetching the latest allows us to make adjustments to the infra without having to copy scripts in to the test infrastructure. 5. based on the hypervisor chosen we choose a profile for cobbler to reimage the hosts in the infrastructure. if xen is chosen we bring up the profile of the latest xen kickstart available in cobbler. currently - this is at xen 6.0.2. if kvm is chosen we can pick between ubuntu and rhel based host OS kickstarts. diff --git a/ui/README.md b/ui/README.md index b7ce7b5cc2b..6e11b318c93 100644 --- a/ui/README.md +++ b/ui/README.md @@ -62,7 +62,7 @@ Fix issues and vulnerabilities: npm audit -A basic development guide and explaination of the basic components can be found +A basic development guide and explanation of the basic components can be found [here](docs/development.md) ## Production diff --git a/ui/docs/full-test-plan.template.md b/ui/docs/full-test-plan.template.md index bced2703701..a93959ad10c 100644 --- a/ui/docs/full-test-plan.template.md +++ b/ui/docs/full-test-plan.template.md @@ -484,7 +484,7 @@ This requires configuring and setting up CKS: http://docs.cloudstack.apache.org/ - [ ] Disable/enable host - [ ] Enable/cancel maintenance mode - [ ] Enable/disable out-of-band management -- [ ] Enable/disale HA +- [ ] Enable/disable HA - [ ] Delete host (only if disabled) **Infrastructure > Primary Storage** diff --git a/ui/docs/smoke-test-plan.template.md b/ui/docs/smoke-test-plan.template.md index cc065ed7bf7..b748874335e 100644 --- a/ui/docs/smoke-test-plan.template.md +++ b/ui/docs/smoke-test-plan.template.md @@ -58,7 +58,7 @@ This requires configuring and setting up CKS: http://docs.cloudstack.apache.org/ **VPC** - [ ] Add VPC -- [ ] VPC actions - updat, restart, delete +- [ ] VPC actions - update, restart, delete - [ ] Add security group - [ ] Add/delete ingress/egress rule diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 380aebe7a1d..e257d0e1dfa 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -647,9 +647,9 @@ "label.create.template": "Create Template", "label.create.tier.aclid.description": "The ACL associated with the Network Tier.", "label.create.tier.externalid.description": "ID of the Network in an external system.", -"label.create.tier.gateway.description": "The Network Tier's gateway in the super CIDR range, not overlapping with the CIDR of other Network Tiers in this VPC.", +"label.create.tier.gateway.description": "Gateway IP must be within VPC CIDR ({value})", "label.create.tier.name.description": "A unique name for the Network Tier.", -"label.create.tier.netmask.description": "The Network Tier's netmask. For example 255.255.255.0", +"label.create.tier.netmask.description": "Network Tier's netmask must be more restrictive than {value}", "label.create.tier.networkofferingid.description": "The Network offering for the Network Tier.", "label.create.tungsten.routing.policy": "Create Tungsten-Fabric routing policy", "label.create.user": "Create User", @@ -676,6 +676,8 @@ "label.dark.mode": "Dark mode", "label.dashboard": "Dashboard", "label.data.disk": "Data disk", +"label.data.pool": "Data pool", +"label.data.pool.description": "Data pool is required when using a Ceph pool with erasure code", "label.data.disk.offering": "Data disk offering", "label.date": "Date", "label.datetime.filter.period": "From {startDate} to {endDate}", diff --git a/ui/public/locales/pt_BR.json b/ui/public/locales/pt_BR.json index dc72ec023bb..aadbd2fedc3 100644 --- a/ui/public/locales/pt_BR.json +++ b/ui/public/locales/pt_BR.json @@ -463,6 +463,8 @@ "label.dashboard": "Dashboard", "label.data.disk": "Disco de dados", "label.data.disk.offering": "Oferta de disco adicional", +"label.data.pool": "Data pool", +"label.data.pool.description": "\u00c9 necess\u00e1rio informar um data pool ao utilizar um Ceph pool com erasure code", "label.date": "Data", "label.day": "Dia", "label.day.of.month": "Dia do m\u00eas", diff --git a/ui/src/components/view/DetailsTab.vue b/ui/src/components/view/DetailsTab.vue index d76da5f0d45..9e9cef48eb2 100644 --- a/ui/src/components/view/DetailsTab.vue +++ b/ui/src/components/view/DetailsTab.vue @@ -159,6 +159,13 @@
{{ $toLocaleDate(dataResource[item]) }}
+ +
+ {{ $t('label.data.pool') }} +
+
{{ dataResource[item].rbd_default_data_pool }}
+
+
@@ -215,7 +222,7 @@ export default { }, computed: { customDisplayItems () { - var items = ['ip4routes', 'ip6routes', 'privatemtu', 'publicmtu', 'provider'] + var items = ['ip4routes', 'ip6routes', 'privatemtu', 'publicmtu', 'provider', 'details'] if (this.$route.meta.name === 'webhookdeliveries') { items.push('startdate') items.push('enddate') diff --git a/ui/src/components/view/InfoCard.vue b/ui/src/components/view/InfoCard.vue index 3e6c193908e..5d9fc60b97a 100644 --- a/ui/src/components/view/InfoCard.vue +++ b/ui/src/components/view/InfoCard.vue @@ -1238,6 +1238,9 @@ export default { if (item.name === 'template') { query.templatefilter = 'self' query.filter = 'self' + } else if (item.name === 'iso') { + query.isofilter = 'self' + query.filter = 'self' } if (item.param === 'account') { diff --git a/ui/src/components/view/ResourceLimitTab.vue b/ui/src/components/view/ResourceLimitTab.vue index 50d8e30735c..0d56468e90f 100644 --- a/ui/src/components/view/ResourceLimitTab.vue +++ b/ui/src/components/view/ResourceLimitTab.vue @@ -27,7 +27,7 @@ >
- - - - - - - - - -
- - - - {{ item.value }} - -
- - -
-
+ + + +
diff --git a/ui/src/views/infra/zone/ZoneWizardAddResources.vue b/ui/src/views/infra/zone/ZoneWizardAddResources.vue index 00811ed3a10..76b90bd3661 100644 --- a/ui/src/views/infra/zone/ZoneWizardAddResources.vue +++ b/ui/src/views/infra/zone/ZoneWizardAddResources.vue @@ -469,7 +469,7 @@ export default { title: 'label.rados.monitor', key: 'primaryStorageRADOSMonitor', placeHolder: 'message.error.rados.monitor', - required: false, + required: true, display: { primaryStorageProtocol: ['rbd'] } @@ -478,6 +478,14 @@ export default { title: 'label.rados.pool', key: 'primaryStorageRADOSPool', placeHolder: 'message.error.rados.pool', + required: true, + display: { + primaryStorageProtocol: ['rbd'] + } + }, + { + title: 'label.data.pool', + key: 'primaryStorageDataPool', required: false, display: { primaryStorageProtocol: ['rbd'] @@ -487,7 +495,7 @@ export default { title: 'label.rados.user', key: 'primaryStorageRADOSUser', placeHolder: 'message.error.rados.user', - required: false, + required: true, display: { primaryStorageProtocol: ['rbd'] } @@ -496,7 +504,7 @@ export default { title: 'label.rados.secret', key: 'primaryStorageRADOSSecret', placeHolder: 'message.error.rados.secret', - required: false, + required: true, display: { primaryStorageProtocol: ['rbd'] } diff --git a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue index 01006cd0c72..a0d7c142a44 100644 --- a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue +++ b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue @@ -1486,6 +1486,10 @@ export default { const rbdpool = this.prefillContent?.primaryStorageRADOSPool || '' const rbdid = this.prefillContent?.primaryStorageRADOSUser || '' const rbdsecret = this.prefillContent?.primaryStorageRADOSSecret || '' + + if (this.prefillContent?.primaryStorageDataPool) { + params['details[0].rbd_default_data_pool'] = this.prefillContent.primaryStorageDataPool + } url = this.rbdURL(rbdmonitor, rbdpool, rbdid, rbdsecret) } else if (protocol === 'Linstor') { url = this.linstorURL(server) diff --git a/ui/src/views/network/VpcTiersTab.vue b/ui/src/views/network/VpcTiersTab.vue index 5d985ae7688..8f1746ecea9 100644 --- a/ui/src/views/network/VpcTiersTab.vue +++ b/ui/src/views/network/VpcTiersTab.vue @@ -242,18 +242,18 @@
@@ -363,6 +363,7 @@ import { api } from '@/api' import { mixinForm } from '@/utils/mixin' import Status from '@/components/widgets/Status' import TooltipLabel from '@/components/widgets/TooltipLabel' +import { getNetmaskFromCidr } from '@/utils/network' export default { name: 'VpcTiersTab', @@ -400,6 +401,8 @@ export default { selectedNetworkOffering: {}, privateMtuMax: 1500, errorPrivateMtu: '', + gatewayPlaceholder: '', + netmaskPlaceholder: '', algorithms: { Source: 'source', 'Round-robin': 'roundrobin', @@ -625,9 +628,9 @@ export default { if (this.publicLBExists && (idx === -1 || this.lbProviderMap.publicLb.vpc.indexOf(offering.service.map(svc => { return svc.provider[0].name })[idx]) === -1)) { filteredOfferings.push(offering) } else if (!this.publicLBExists && vpcLbServiceIndex > -1) { - const vpcLbServiceProvider = vpcLbServiceIndex === -1 ? undefined : this.resource.service[vpcLbServiceIndex].provider[0].name + const vpcLbServiceProviders = vpcLbServiceIndex === -1 ? undefined : this.resource.service[vpcLbServiceIndex].provider.map(provider => provider.name) const offeringLbServiceProvider = idx === -1 ? undefined : offering.service[idx].provider[0].name - if (vpcLbServiceProvider && (!offeringLbServiceProvider || (offeringLbServiceProvider && vpcLbServiceProvider === offeringLbServiceProvider))) { + if (vpcLbServiceProviders && (!offeringLbServiceProvider || (offeringLbServiceProvider && vpcLbServiceProviders.includes(offeringLbServiceProvider)))) { filteredOfferings.push(offering) } } else { @@ -696,6 +699,13 @@ export default { this.initForm() this.fetchNetworkAclList() this.fetchNetworkOfferings() + const cidr = this.resource.cidr + const netmask = getNetmaskFromCidr(cidr) + if (netmask) { + this.gatewayPlaceholder = this.$t('label.create.tier.gateway.description', { value: cidr }) + this.netmaskPlaceholder = this.$t('label.create.tier.netmask.description', { value: netmask }) + } + this.showCreateNetworkModal = true this.rules = { name: [{ required: true, message: this.$t('label.required') }], diff --git a/ui/src/views/setting/ConfigurationTable.vue b/ui/src/views/setting/ConfigurationTable.vue index 68548526b38..56518d2570b 100644 --- a/ui/src/views/setting/ConfigurationTable.vue +++ b/ui/src/views/setting/ConfigurationTable.vue @@ -37,6 +37,7 @@ { + } + api('resetConfiguration', params).then(json => { this.editableValue = this.getEditableValue(json.resetconfigurationresponse.configuration) this.actualValue = this.editableValue var newValue = this.editableValue diff --git a/utils/src/main/java/com/cloud/utils/nio/HandlerFactory.java b/utils/src/main/java/com/cloud/utils/nio/HandlerFactory.java index 6f0f1945e01..9493f24b92b 100644 --- a/utils/src/main/java/com/cloud/utils/nio/HandlerFactory.java +++ b/utils/src/main/java/com/cloud/utils/nio/HandlerFactory.java @@ -25,7 +25,7 @@ import java.net.SocketAddress; * WorkerFactory creates and selects workers. */ public interface HandlerFactory { - public Task create(Task.Type type, Link link, byte[] data); + Task create(Task.Type type, Link link, byte[] data); default int getMaxConcurrentNewConnectionsCount() { return 0; } diff --git a/utils/src/main/java/com/cloud/utils/nio/Link.java b/utils/src/main/java/com/cloud/utils/nio/Link.java index 5404cd15343..4e68554eb49 100644 --- a/utils/src/main/java/com/cloud/utils/nio/Link.java +++ b/utils/src/main/java/com/cloud/utils/nio/Link.java @@ -617,8 +617,8 @@ public class Link { final long timeTaken = System.currentTimeMillis() - startTimeMills; if (timeTaken > timeoutMillis) { - LOGGER.warn("SSL Handshake has taken more than {}ms to connect to: {}" + - " while status: {}. Please investigate this connection.", socketChannel.getRemoteAddress(), + LOGGER.warn("SSL Handshake has taken more than {} ms to connect to: {}" + + " while status: {}. Please investigate this connection.", timeoutMillis, socketChannel.getRemoteAddress(), handshakeStatus); return false; } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioClient.java b/utils/src/main/java/com/cloud/utils/nio/NioClient.java index 46d67feaaf3..d274973a658 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioClient.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioClient.java @@ -115,4 +115,8 @@ public class NioClient extends NioConnection { } logger.info("NioClient connection closed"); } + + public String getHost() { + return host; + } } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java index 98fa69716cd..ed6b5748289 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java @@ -83,26 +83,19 @@ public abstract class NioConnection implements Callable { protected Set socketChannels = new HashSet<>(); protected Integer sslHandshakeTimeout = null; private final int factoryMaxNewConnectionsCount; + protected boolean blockNewConnections; public NioConnection(final String name, final int port, final int workers, final HandlerFactory factory) { _name = name; _isRunning = false; + blockNewConnections = false; _selector = null; _port = port; _workers = workers; _factory = factory; this.factoryMaxNewConnectionsCount = factory.getMaxConcurrentNewConnectionsCount(); - _executor = new ThreadPoolExecutor(workers, 5 * workers, 1, TimeUnit.DAYS, - new LinkedBlockingQueue<>(5 * workers), new NamedThreadFactory(name + "-Handler"), - new ThreadPoolExecutor.AbortPolicy()); - String sslHandshakeHandlerName = name + "-SSLHandshakeHandler"; - if (factoryMaxNewConnectionsCount > 0) { - _sslHandshakeExecutor = new ThreadPoolExecutor(0, this.factoryMaxNewConnectionsCount, 30, - TimeUnit.MINUTES, new SynchronousQueue<>(), new NamedThreadFactory(sslHandshakeHandlerName), - new ThreadPoolExecutor.AbortPolicy()); - } else { - _sslHandshakeExecutor = Executors.newCachedThreadPool(new NamedThreadFactory(sslHandshakeHandlerName)); - } + initWorkersExecutor(); + initSSLHandshakeExecutor(); } public void setCAService(final CAService caService) { @@ -127,10 +120,14 @@ public abstract class NioConnection implements Callable { _isStartup = true; if (_executor.isShutdown()) { - _executor = new ThreadPoolExecutor(_workers, 5 * _workers, 1, TimeUnit.DAYS, new LinkedBlockingQueue<>(), new NamedThreadFactory(_name + "-Handler")); + initWorkersExecutor(); + } + if (_sslHandshakeExecutor.isShutdown()) { + initSSLHandshakeExecutor(); } _threadExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory(this._name + "-NioConnectionHandler")); _isRunning = true; + blockNewConnections = false; _futureTask = _threadExecutor.submit(this); } @@ -138,12 +135,30 @@ public abstract class NioConnection implements Callable { _executor.shutdown(); _sslHandshakeExecutor.shutdown(); _isRunning = false; + blockNewConnections = true; if (_threadExecutor != null) { _futureTask.cancel(false); _threadExecutor.shutdown(); } } + private void initWorkersExecutor() { + _executor = new ThreadPoolExecutor(_workers, 5 * _workers, 1, TimeUnit.DAYS, + new LinkedBlockingQueue<>(5 * _workers), new NamedThreadFactory(_name + "-Handler"), + new ThreadPoolExecutor.AbortPolicy()); + } + + private void initSSLHandshakeExecutor() { + String sslHandshakeHandlerName = _name + "-SSLHandshakeHandler"; + if (factoryMaxNewConnectionsCount > 0) { + _sslHandshakeExecutor = new ThreadPoolExecutor(0, this.factoryMaxNewConnectionsCount, 30, + TimeUnit.MINUTES, new SynchronousQueue<>(), new NamedThreadFactory(sslHandshakeHandlerName), + new ThreadPoolExecutor.AbortPolicy()); + } else { + _sslHandshakeExecutor = Executors.newCachedThreadPool(new NamedThreadFactory(sslHandshakeHandlerName)); + } + } + public boolean isRunning() { return !_futureTask.isDone(); } @@ -210,6 +225,16 @@ public abstract class NioConnection implements Callable { abstract void unregisterLink(InetSocketAddress saddr); + protected boolean rejectConnectionIfBlocked(final SocketChannel socketChannel) throws IOException { + if (!blockNewConnections) { + return false; + } + logger.warn("Rejecting new connection as the server is blocked from accepting new connections"); + socketChannel.close(); + _selector.wakeup(); + return true; + } + protected boolean rejectConnectionIfBusy(final SocketChannel socketChannel) throws IOException { if (factoryMaxNewConnectionsCount <= 0 || _factory.getNewConnectionsCount() < factoryMaxNewConnectionsCount) { return false; @@ -226,7 +251,7 @@ public abstract class NioConnection implements Callable { protected void accept(final SelectionKey key) throws IOException { final ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel(); final SocketChannel socketChannel = serverSocketChannel.accept(); - if (rejectConnectionIfBusy(socketChannel)) { + if (rejectConnectionIfBlocked(socketChannel) || rejectConnectionIfBusy(socketChannel)) { return; } socketChannel.configureBlocking(false); @@ -520,6 +545,14 @@ public abstract class NioConnection implements Callable { } } + public void block() { + blockNewConnections = true; + } + + public void unblock() { + blockNewConnections = false; + } + public class ChangeRequest { public static final int REGISTER = 1; public static final int CHANGEOPS = 2;