diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/consoleproxy/ConsoleEndpoint.java b/api/src/main/java/org/apache/cloudstack/api/command/user/consoleproxy/ConsoleEndpoint.java index cd61c223ed1..4b47a60b27e 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/consoleproxy/ConsoleEndpoint.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/consoleproxy/ConsoleEndpoint.java @@ -21,6 +21,10 @@ public class ConsoleEndpoint { private boolean result; private String details; private String url; + private String websocketToken; + private String websocketPath; + private String websocketHost; + private String websocketPort; public ConsoleEndpoint(boolean result, String url) { this.result = result; @@ -55,4 +59,36 @@ public class ConsoleEndpoint { public void setDetails(String details) { this.details = details; } + + public String getWebsocketToken() { + return websocketToken; + } + + public void setWebsocketToken(String websocketToken) { + this.websocketToken = websocketToken; + } + + public String getWebsocketPath() { + return websocketPath; + } + + public void setWebsocketPath(String websocketPath) { + this.websocketPath = websocketPath; + } + + public String getWebsocketHost() { + return websocketHost; + } + + public void setWebsocketHost(String websocketHost) { + this.websocketHost = websocketHost; + } + + public String getWebsocketPort() { + return websocketPort; + } + + public void setWebsocketPort(String websocketPort) { + this.websocketPort = websocketPort; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/consoleproxy/CreateConsoleEndpointCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/consoleproxy/CreateConsoleEndpointCmd.java index b84fa474510..870d4f11d2c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/consoleproxy/CreateConsoleEndpointCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/consoleproxy/CreateConsoleEndpointCmd.java @@ -27,7 +27,8 @@ import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.CreateConsoleUrlResponse; +import org.apache.cloudstack.api.response.ConsoleEndpointWebsocketResponse; +import org.apache.cloudstack.api.response.CreateConsoleEndpointResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.consoleproxy.ConsoleAccessManager; import org.apache.cloudstack.context.CallContext; @@ -39,7 +40,7 @@ import javax.inject.Inject; import java.util.Map; @APICommand(name = CreateConsoleEndpointCmd.APINAME, description = "Create a console endpoint to connect to a VM console", - responseObject = CreateConsoleUrlResponse.class, since = "4.18.0", + responseObject = CreateConsoleEndpointResponse.class, since = "4.18.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class CreateConsoleEndpointCmd extends BaseCmd { @@ -62,18 +63,34 @@ public class CreateConsoleEndpointCmd extends BaseCmd { String clientAddress = getClientAddress(); ConsoleEndpoint endpoint = consoleManager.generateConsoleEndpoint(vmId, clientSecurityToken, clientAddress); if (endpoint != null) { - CreateConsoleUrlResponse response = new CreateConsoleUrlResponse(); - response.setResult(endpoint.isResult()); - response.setDetails(endpoint.getDetails()); - response.setUrl(endpoint.getUrl()); - response.setResponseName(getCommandName()); - response.setObjectName("consoleendpoint"); + CreateConsoleEndpointResponse response = createResponse(endpoint); setResponseObject(response); } else { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to generate console endpoint for vm " + vmId); } } + private CreateConsoleEndpointResponse createResponse(ConsoleEndpoint endpoint) { + CreateConsoleEndpointResponse response = new CreateConsoleEndpointResponse(); + response.setResult(endpoint.isResult()); + response.setDetails(endpoint.getDetails()); + response.setUrl(endpoint.getUrl()); + response.setWebsocketResponse(createWebsocketResponse(endpoint)); + response.setResponseName(getCommandName()); + response.setObjectName("consoleendpoint"); + return response; + } + + private ConsoleEndpointWebsocketResponse createWebsocketResponse(ConsoleEndpoint endpoint) { + ConsoleEndpointWebsocketResponse wsResponse = new ConsoleEndpointWebsocketResponse(); + wsResponse.setHost(endpoint.getWebsocketHost()); + wsResponse.setPort(endpoint.getWebsocketPort()); + wsResponse.setPath(endpoint.getWebsocketPath()); + wsResponse.setToken(endpoint.getWebsocketToken()); + wsResponse.setObjectName("websocket"); + return wsResponse; + } + private String getParameterBase(String paramKey) { Map params = getFullUrlParams(); return MapUtils.isNotEmpty(params) && params.containsKey(paramKey) ? params.get(paramKey) : null; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ConsoleEndpointWebsocketResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ConsoleEndpointWebsocketResponse.java new file mode 100644 index 00000000000..a453a123790 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/ConsoleEndpointWebsocketResponse.java @@ -0,0 +1,76 @@ +// 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.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +public class ConsoleEndpointWebsocketResponse extends BaseResponse { + + public ConsoleEndpointWebsocketResponse() { + } + + @SerializedName(ApiConstants.TOKEN) + @Param(description = "the console websocket token") + private String token; + + @SerializedName("host") + @Param(description = "the console websocket host") + private String host; + + @SerializedName(ApiConstants.PORT) + @Param(description = "the console websocket port") + private String port; + + @SerializedName(ApiConstants.PATH) + @Param(description = "the console websocket path") + private String path; + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/CreateConsoleUrlResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/CreateConsoleEndpointResponse.java similarity index 69% rename from api/src/main/java/org/apache/cloudstack/api/response/CreateConsoleUrlResponse.java rename to api/src/main/java/org/apache/cloudstack/api/response/CreateConsoleEndpointResponse.java index 61b05be7ab3..c60917bbe7a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/CreateConsoleUrlResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/CreateConsoleEndpointResponse.java @@ -21,7 +21,10 @@ import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; -public class CreateConsoleUrlResponse extends BaseResponse { +public class CreateConsoleEndpointResponse extends BaseResponse { + + public CreateConsoleEndpointResponse() { + } @SerializedName(ApiConstants.RESULT) @Param(description = "true if the console endpoint is generated properly") @@ -31,22 +34,14 @@ public class CreateConsoleUrlResponse extends BaseResponse { @Param(description = "details in case of an error") private String details; - @SerializedName(ApiConstants.IP_ADDRESS) - @Param(description = "the console ip address") - private String ipAddress; - - @SerializedName(ApiConstants.PORT) - @Param(description = "the console port") - private String port; - - @SerializedName(ApiConstants.TOKEN) - @Param(description = "the console token") - private String token; - @SerializedName(ApiConstants.URL) @Param(description = "the console url") private String url; + @SerializedName("websocket") + @Param(description = "the console websocket options") + private ConsoleEndpointWebsocketResponse websocketResponse; + public Boolean getResult() { return result; } @@ -63,30 +58,6 @@ public class CreateConsoleUrlResponse extends BaseResponse { this.details = details; } - public String getIpAddress() { - return ipAddress; - } - - public void setIpAddress(String ip) { - this.ipAddress = ip; - } - - public String getPort() { - return port; - } - - public void setPort(String port) { - this.port = port; - } - - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } - public String getUrl() { return url; } @@ -94,4 +65,12 @@ public class CreateConsoleUrlResponse extends BaseResponse { public void setUrl(String url) { this.url = url; } + + public ConsoleEndpointWebsocketResponse getWebsocketResponse() { + return websocketResponse; + } + + public void setWebsocketResponse(ConsoleEndpointWebsocketResponse websocketResponse) { + this.websocketResponse = websocketResponse; + } } diff --git a/api/src/main/java/org/apache/cloudstack/consoleproxy/ConsoleAccessManager.java b/api/src/main/java/org/apache/cloudstack/consoleproxy/ConsoleAccessManager.java index 69e12d47438..38c71a7b38e 100644 --- a/api/src/main/java/org/apache/cloudstack/consoleproxy/ConsoleAccessManager.java +++ b/api/src/main/java/org/apache/cloudstack/consoleproxy/ConsoleAccessManager.java @@ -23,11 +23,6 @@ import org.apache.cloudstack.framework.config.Configurable; public interface ConsoleAccessManager extends Manager, Configurable { - - ConfigKey ConsoleProxySchema = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED, String.class, - "consoleproxy.schema", "http", - "The http/https schema to be used by the console proxy URLs", true); - ConfigKey ConsoleProxyExtraSecurityHeaderEnabled = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED, Boolean.class, "consoleproxy.extra.security.header.enabled", "false", "Enable/disable extra security validation for console proxy using client header", true); diff --git a/server/src/main/java/com/cloud/consoleproxy/ConsoleAccessManagerImpl.java b/server/src/main/java/com/cloud/consoleproxy/ConsoleAccessManagerImpl.java index 75bd6cddef9..26e51f804d1 100644 --- a/server/src/main/java/com/cloud/consoleproxy/ConsoleAccessManagerImpl.java +++ b/server/src/main/java/com/cloud/consoleproxy/ConsoleAccessManagerImpl.java @@ -317,7 +317,13 @@ public class ConsoleAccessManagerImpl extends ManagerBase implements ConsoleAcce } s_logger.debug("Adding allowed session: " + sessionUuid); allowedSessions.add(sessionUuid); - String url = !sb.toString().startsWith("http") ? ConsoleAccessManager.ConsoleProxySchema.value() + ":" + sb : sb.toString(); + + String url = !sb.toString().startsWith("https") ? sb.toString() : "http:" + sb; + ConsoleEndpoint consoleEndpoint = new ConsoleEndpoint(true, url); + consoleEndpoint.setWebsocketHost(managementServer.getConsoleAccessAddress(vm.getId())); + consoleEndpoint.setWebsocketPort(String.valueOf(ConsoleProxyManager.NoVncConsolePort.value())); + consoleEndpoint.setWebsocketPath("websockify"); + consoleEndpoint.setWebsocketToken(token); return new ConsoleEndpoint(true, url); } @@ -443,7 +449,7 @@ public class ConsoleAccessManagerImpl extends ManagerBase implements ConsoleAcce @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] { ConsoleProxySchema, ConsoleProxyExtraSecurityHeaderName, + return new ConfigKey[] { ConsoleProxyExtraSecurityHeaderName, ConsoleProxyExtraSecurityHeaderEnabled }; } } diff --git a/server/src/main/java/com/cloud/server/ManagementServer.java b/server/src/main/java/com/cloud/server/ManagementServer.java index 4e58a4f5576..cd0135ec7ae 100644 --- a/server/src/main/java/com/cloud/server/ManagementServer.java +++ b/server/src/main/java/com/cloud/server/ManagementServer.java @@ -53,6 +53,8 @@ public interface ManagementServer extends ManagementService, PluggableService { String getConsoleAccessUrlRoot(long vmId); + String getConsoleAccessAddress(long vmId); + GuestOSVO getGuestOs(Long guestOsId); GuestOSHypervisorVO getGuestOsHypervisor(Long guestOsHypervisorId); diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 5f599492339..ee3cafd2eda 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -2736,6 +2736,16 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe return null; } + @Override + public String getConsoleAccessAddress(long vmId) { + final VMInstanceVO vm = _vmInstanceDao.findById(vmId); + if (vm != null) { + final ConsoleProxyInfo proxy = getConsoleProxyForVm(vm.getDataCenterId(), vmId); + return proxy != null ? proxy.getProxyAddress() : null; + } + return null; + } + @Override public Pair getVncPort(final VirtualMachine vm) { if (vm.getHostId() == null) {