This commit is contained in:
David Nalley 2012-08-07 19:05:34 -04:00
commit dd949aebaf
14 changed files with 2225 additions and 3881 deletions

View File

@ -1,22 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>

View File

@ -241,7 +241,7 @@
<available file="${setup.db.dir}/override/templates.sql" />
</condition>
<echo message="deploydb ${server-setup.file} ${templates.file} ${DBROOTPW}" />
<echo message="${db.scripts.dir}\\deploy-db-dev.sh ${server-setup.file} ${templates.file} ${DBROOTPW}" />
<exec dir="${db.scripts.dir}" executable="bash" failonerror="true">
<arg value="deploy-db-dev.sh" />
<arg value="${server-setup.file}" />

View File

@ -53,6 +53,7 @@ import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.ConnectionClosedException;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
@ -112,7 +113,6 @@ import com.cloud.utils.component.PluggableService;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.encoding.Base64;
import com.cloud.utils.exception.CSExceptionErrorCode;
import com.cloud.uuididentity.dao.IdentityDao;
@ -432,31 +432,31 @@ public class ApiServer implements HttpRequestHandler {
}
} catch (Exception ex) {
if (ex instanceof InvalidParameterValueException) {
InvalidParameterValueException ref = (InvalidParameterValueException)ex;
ServerApiException e = new ServerApiException(BaseCmd.PARAM_ERROR, ex.getMessage());
InvalidParameterValueException ref = (InvalidParameterValueException)ex;
ServerApiException e = new ServerApiException(BaseCmd.PARAM_ERROR, ex.getMessage());
// copy over the IdentityProxy information as well and throw the serverapiexception.
ArrayList<IdentityProxy> idList = ref.getIdProxyList();
if (idList != null) {
// Iterate through entire arraylist and copy over each proxy id.
for (int i = 0 ; i < idList.size(); i++) {
IdentityProxy obj = idList.get(i);
e.addProxyObject(obj.getTableName(), obj.getValue(), obj.getidFieldName());
}
// Iterate through entire arraylist and copy over each proxy id.
for (int i = 0 ; i < idList.size(); i++) {
IdentityProxy obj = idList.get(i);
e.addProxyObject(obj.getTableName(), obj.getValue(), obj.getidFieldName());
}
}
// Also copy over the cserror code and the function/layer in which it was thrown.
e.setCSErrorCode(ref.getCSErrorCode());
e.setCSErrorCode(ref.getCSErrorCode());
throw e;
} else if (ex instanceof PermissionDeniedException) {
PermissionDeniedException ref = (PermissionDeniedException)ex;
ServerApiException e = new ServerApiException(BaseCmd.ACCOUNT_ERROR, ex.getMessage());
PermissionDeniedException ref = (PermissionDeniedException)ex;
ServerApiException e = new ServerApiException(BaseCmd.ACCOUNT_ERROR, ex.getMessage());
// copy over the IdentityProxy information as well and throw the serverapiexception.
ArrayList<IdentityProxy> idList = ref.getIdProxyList();
ArrayList<IdentityProxy> idList = ref.getIdProxyList();
if (idList != null) {
// Iterate through entire arraylist and copy over each proxy id.
for (int i = 0 ; i < idList.size(); i++) {
IdentityProxy obj = idList.get(i);
e.addProxyObject(obj.getTableName(), obj.getValue(), obj.getidFieldName());
}
// Iterate through entire arraylist and copy over each proxy id.
for (int i = 0 ; i < idList.size(); i++) {
IdentityProxy obj = idList.get(i);
e.addProxyObject(obj.getTableName(), obj.getValue(), obj.getidFieldName());
}
}
e.setCSErrorCode(ref.getCSErrorCode());
throw e;
@ -751,7 +751,7 @@ public class ApiServer implements HttpRequestHandler {
mac.init(keySpec);
mac.update(unsignedRequest.getBytes());
byte[] encryptedBytes = mac.doFinal();
String computedSignature = Base64.encodeBytes(encryptedBytes);
String computedSignature = Base64.encodeBase64URLSafeString(encryptedBytes);
boolean equalSig = signature.equals(computedSignature);
if (!equalSig) {
s_logger.info("User signature: " + signature + " is not equaled to computed signature: " + computedSignature);
@ -765,7 +765,7 @@ public class ApiServer implements HttpRequestHandler {
}
return false;
}
public Long fetchDomainId(String domainUUID){
ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name);
IdentityDao identityDao = locator.getDao(IdentityDao.class);
@ -816,19 +816,19 @@ public class ApiServer implements HttpRequestHandler {
if(user.getUuid() != null){
session.setAttribute("user_UUID", user.getUuid());
}
session.setAttribute("username", userAcct.getUsername());
session.setAttribute("firstname", userAcct.getFirstname());
session.setAttribute("lastname", userAcct.getLastname());
session.setAttribute("accountobj", account);
session.setAttribute("account", account.getAccountName());
session.setAttribute("domainid", account.getDomainId());
DomainVO domain = (DomainVO) _domainMgr.getDomain(account.getDomainId());
if(domain.getUuid() != null){
session.setAttribute("domain_UUID", domain.getUuid());
}
session.setAttribute("type", Short.valueOf(account.getType()).toString());
session.setAttribute("registrationtoken", userAcct.getRegistrationToken());
session.setAttribute("registered", new Boolean(userAcct.isRegistered()).toString());
@ -843,7 +843,7 @@ public class ApiServer implements HttpRequestHandler {
SecureRandom sesssionKeyRandom = new SecureRandom();
byte sessionKeyBytes[] = new byte[20];
sesssionKeyRandom.nextBytes(sessionKeyBytes);
String sessionKey = Base64.encodeBytes(sessionKeyBytes);
String sessionKey = Base64.encodeBase64URLSafeString(sessionKeyBytes);
session.setAttribute("sessionkey", sessionKey);
return;
@ -938,8 +938,8 @@ public class ApiServer implements HttpRequestHandler {
_params = new BasicHttpParams();
_params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 30000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
// Set up the HTTP protocol processor
BasicHttpProcessor httpproc = new BasicHttpProcessor();
@ -1053,44 +1053,44 @@ public class ApiServer implements HttpRequestHandler {
// Exception. When invoked from ApiServlet's processRequest(), this can be
// a standard exception like NumberFormatException. We'll leave the standard ones alone.
if (ex != null) {
if (ex instanceof ServerApiException || ex instanceof PermissionDeniedException
|| ex instanceof InvalidParameterValueException) {
// Cast the exception appropriately and retrieve the IdentityProxy
if (ex instanceof ServerApiException) {
ServerApiException ref = (ServerApiException) ex;
ArrayList<IdentityProxy> idList = ref.getIdProxyList();
if (idList != null) {
for (int i=0; i < idList.size(); i++) {
IdentityProxy id = idList.get(i);
apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName());
}
}
// Also copy over the cserror code and the function/layer in which it was thrown.
apiResponse.setCSErrorCode(ref.getCSErrorCode());
} else if (ex instanceof PermissionDeniedException) {
PermissionDeniedException ref = (PermissionDeniedException) ex;
ArrayList<IdentityProxy> idList = ref.getIdProxyList();
if (idList != null) {
for (int i=0; i < idList.size(); i++) {
IdentityProxy id = idList.get(i);
apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName());
}
}
// Also copy over the cserror code and the function/layer in which it was thrown.
apiResponse.setCSErrorCode(ref.getCSErrorCode());
} else if (ex instanceof InvalidParameterValueException) {
InvalidParameterValueException ref = (InvalidParameterValueException) ex;
ArrayList<IdentityProxy> idList = ref.getIdProxyList();
if (idList != null) {
for (int i=0; i < idList.size(); i++) {
IdentityProxy id = idList.get(i);
apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName());
}
}
// Also copy over the cserror code and the function/layer in which it was thrown.
apiResponse.setCSErrorCode(ref.getCSErrorCode());
}
}
if (ex instanceof ServerApiException || ex instanceof PermissionDeniedException
|| ex instanceof InvalidParameterValueException) {
// Cast the exception appropriately and retrieve the IdentityProxy
if (ex instanceof ServerApiException) {
ServerApiException ref = (ServerApiException) ex;
ArrayList<IdentityProxy> idList = ref.getIdProxyList();
if (idList != null) {
for (int i=0; i < idList.size(); i++) {
IdentityProxy id = idList.get(i);
apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName());
}
}
// Also copy over the cserror code and the function/layer in which it was thrown.
apiResponse.setCSErrorCode(ref.getCSErrorCode());
} else if (ex instanceof PermissionDeniedException) {
PermissionDeniedException ref = (PermissionDeniedException) ex;
ArrayList<IdentityProxy> idList = ref.getIdProxyList();
if (idList != null) {
for (int i=0; i < idList.size(); i++) {
IdentityProxy id = idList.get(i);
apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName());
}
}
// Also copy over the cserror code and the function/layer in which it was thrown.
apiResponse.setCSErrorCode(ref.getCSErrorCode());
} else if (ex instanceof InvalidParameterValueException) {
InvalidParameterValueException ref = (InvalidParameterValueException) ex;
ArrayList<IdentityProxy> idList = ref.getIdProxyList();
if (idList != null) {
for (int i=0; i < idList.size(); i++) {
IdentityProxy id = idList.get(i);
apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName());
}
}
// Also copy over the cserror code and the function/layer in which it was thrown.
apiResponse.setCSErrorCode(ref.getCSErrorCode());
}
}
}
SerializationContext.current().setUuidTranslation(true);
responseText = ApiResponseSerializer.toSerializedString(apiResponse, responseType);

View File

@ -58,61 +58,61 @@ import com.cloud.vm.VirtualMachineManager;
* Authentication : /console?cmd=auth&vm=xxx&sid=xxx
*/
public class ConsoleProxyServlet extends HttpServlet {
private static final long serialVersionUID = -5515382620323808168L;
public static final Logger s_logger = Logger.getLogger(ConsoleProxyServlet.class.getName());
private static final int DEFAULT_THUMBNAIL_WIDTH = 144;
private static final int DEFAULT_THUMBNAIL_HEIGHT = 110;
private final static AccountManager _accountMgr = ComponentLocator.getLocator(ManagementServer.Name).getManager(AccountManager.class);
private final static VirtualMachineManager _vmMgr = ComponentLocator.getLocator(ManagementServer.Name).getManager(VirtualMachineManager.class);
private final static ManagementServer _ms = (ManagementServer)ComponentLocator.getComponent(ManagementServer.Name);
private final static IdentityService _identityService = (IdentityService)ComponentLocator.getLocator(ManagementServer.Name).getManager(IdentityService.class);
@Override
private static final long serialVersionUID = -5515382620323808168L;
public static final Logger s_logger = Logger.getLogger(ConsoleProxyServlet.class.getName());
private static final int DEFAULT_THUMBNAIL_WIDTH = 144;
private static final int DEFAULT_THUMBNAIL_HEIGHT = 110;
private final static AccountManager _accountMgr = ComponentLocator.getLocator(ManagementServer.Name).getManager(AccountManager.class);
private final static VirtualMachineManager _vmMgr = ComponentLocator.getLocator(ManagementServer.Name).getManager(VirtualMachineManager.class);
private final static ManagementServer _ms = (ManagementServer)ComponentLocator.getComponent(ManagementServer.Name);
private final static IdentityService _identityService = ComponentLocator.getLocator(ManagementServer.Name).getManager(IdentityService.class);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
doGet(req, resp);
}
@Override
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
try {
if(_accountMgr == null || _vmMgr == null || _ms == null) {
sendResponse(resp, "Service is not ready");
return;
}
if(_ms.getHashKey() == null) {
s_logger.debug("Console/thumbnail access denied. Ticket service is not ready yet");
sendResponse(resp, "Service is not ready");
return;
}
try {
if(_accountMgr == null || _vmMgr == null || _ms == null) {
sendResponse(resp, "Service is not ready");
return;
}
if(_ms.getHashKey() == null) {
s_logger.debug("Console/thumbnail access denied. Ticket service is not ready yet");
sendResponse(resp, "Service is not ready");
return;
}
String userId = null;
String account = null;
Account accountObj = null;
Map<String, Object[]> params = new HashMap<String, Object[]>();
params.putAll(req.getParameterMap());
HttpSession session = req.getSession(false);
if(session == null) {
if(verifyRequest(params)) {
if(verifyRequest(params)) {
userId = (String)params.get("userid")[0];
account = (String)params.get("account")[0];
accountObj = (Account)params.get("accountobj")[0];
} else {
s_logger.debug("Invalid web session or API key in request, reject console/thumbnail access");
sendResponse(resp, "Access denied. Invalid web session or API key in request");
return;
}
} else {
s_logger.debug("Invalid web session or API key in request, reject console/thumbnail access");
sendResponse(resp, "Access denied. Invalid web session or API key in request");
return;
}
} else {
// adjust to latest API refactoring changes
if(session.getAttribute("userid") != null) {
// adjust to latest API refactoring changes
if(session.getAttribute("userid") != null) {
userId = ((Long)session.getAttribute("userid")).toString();
}
accountObj = (Account)session.getAttribute("accountobj");
accountObj = (Account)session.getAttribute("accountobj");
if(accountObj != null) {
account = "" + accountObj.getId();
}
@ -120,381 +120,381 @@ public class ConsoleProxyServlet extends HttpServlet {
// Do a sanity check here to make sure the user hasn't already been deleted
if ((userId == null) || (account == null) || (accountObj == null) || !verifyUser(Long.valueOf(userId))) {
s_logger.debug("Invalid user/account, reject console/thumbnail access");
sendResponse(resp, "Access denied. Invalid or inconsistent account is found");
return;
s_logger.debug("Invalid user/account, reject console/thumbnail access");
sendResponse(resp, "Access denied. Invalid or inconsistent account is found");
return;
}
String cmd = req.getParameter("cmd");
if(cmd == null || !isValidCmd(cmd)) {
s_logger.debug("invalid console servlet command: " + cmd);
sendResponse(resp, "");
return;
}
String cmd = req.getParameter("cmd");
if(cmd == null || !isValidCmd(cmd)) {
s_logger.debug("invalid console servlet command: " + cmd);
sendResponse(resp, "");
return;
}
String vmIdString = req.getParameter("vm");
Long vmId = _identityService.getIdentityId("vm_instance", vmIdString);
if(vmId == null) {
s_logger.info("invalid console servlet command parameter: " + vmIdString);
sendResponse(resp, "");
return;
}
if(!checkSessionPermision(req, vmId, accountObj)) {
sendResponse(resp, "Permission denied");
return;
}
if(cmd.equalsIgnoreCase("thumbnail")) {
String vmIdString = req.getParameter("vm");
Long vmId = _identityService.getIdentityId("vm_instance", vmIdString);
if(vmId == null) {
s_logger.info("invalid console servlet command parameter: " + vmIdString);
sendResponse(resp, "");
return;
}
if(!checkSessionPermision(req, vmId, accountObj)) {
sendResponse(resp, "Permission denied");
return;
}
if(cmd.equalsIgnoreCase("thumbnail")) {
handleThumbnailRequest(req, resp, vmId);
} else if(cmd.equalsIgnoreCase("access")) {
handleAccessRequest(req, resp, vmId);
} else {
handleAuthRequest(req, resp, vmId);
}
} catch (Throwable e) {
s_logger.error("Unexepected exception in ConsoleProxyServlet", e);
sendResponse(resp, "Server Internal Error");
}
}
private void handleThumbnailRequest(HttpServletRequest req, HttpServletResponse resp, long vmId) {
VMInstanceVO vm = _vmMgr.findById(vmId);
if(vm == null) {
s_logger.warn("VM " + vmId + " does not exist, sending blank response for thumbnail request");
sendResponse(resp, "");
return;
}
if(vm.getHostId() == null) {
s_logger.warn("VM " + vmId + " lost host info, sending blank response for thumbnail request");
sendResponse(resp, "");
return;
}
HostVO host = _ms.getHostBy(vm.getHostId());
if(host == null) {
s_logger.warn("VM " + vmId + "'s host does not exist, sending blank response for thumbnail request");
sendResponse(resp, "");
return;
}
String rootUrl = _ms.getConsoleAccessUrlRoot(vmId);
if(rootUrl == null) {
sendResponse(resp, "");
return;
}
int w = DEFAULT_THUMBNAIL_WIDTH;
int h = DEFAULT_THUMBNAIL_HEIGHT;
String value = req.getParameter("w");
try {
w = Integer.parseInt(value);
} catch(NumberFormatException e) {
}
value = req.getParameter("h");
try {
h = Integer.parseInt(value);
} catch(NumberFormatException e) {
}
try {
resp.sendRedirect(composeThumbnailUrl(rootUrl, vm, host, w, h));
} catch (IOException e) {
if(s_logger.isInfoEnabled()) {
} catch (Throwable e) {
s_logger.error("Unexepected exception in ConsoleProxyServlet", e);
sendResponse(resp, "Server Internal Error");
}
}
private void handleThumbnailRequest(HttpServletRequest req, HttpServletResponse resp, long vmId) {
VMInstanceVO vm = _vmMgr.findById(vmId);
if(vm == null) {
s_logger.warn("VM " + vmId + " does not exist, sending blank response for thumbnail request");
sendResponse(resp, "");
return;
}
if(vm.getHostId() == null) {
s_logger.warn("VM " + vmId + " lost host info, sending blank response for thumbnail request");
sendResponse(resp, "");
return;
}
HostVO host = _ms.getHostBy(vm.getHostId());
if(host == null) {
s_logger.warn("VM " + vmId + "'s host does not exist, sending blank response for thumbnail request");
sendResponse(resp, "");
return;
}
String rootUrl = _ms.getConsoleAccessUrlRoot(vmId);
if(rootUrl == null) {
sendResponse(resp, "");
return;
}
int w = DEFAULT_THUMBNAIL_WIDTH;
int h = DEFAULT_THUMBNAIL_HEIGHT;
String value = req.getParameter("w");
try {
w = Integer.parseInt(value);
} catch(NumberFormatException e) {
}
value = req.getParameter("h");
try {
h = Integer.parseInt(value);
} catch(NumberFormatException e) {
}
try {
resp.sendRedirect(composeThumbnailUrl(rootUrl, vm, host, w, h));
} catch (IOException e) {
if(s_logger.isInfoEnabled()) {
s_logger.info("Client may already close the connection");
}
}
}
private void handleAccessRequest(HttpServletRequest req, HttpServletResponse resp, long vmId) {
VMInstanceVO vm = _vmMgr.findById(vmId);
if(vm == null) {
s_logger.warn("VM " + vmId + " does not exist, sending blank response for console access request");
sendResponse(resp, "");
return;
}
if(vm.getHostId() == null) {
s_logger.warn("VM " + vmId + " lost host info, sending blank response for console access request");
sendResponse(resp, "");
return;
}
HostVO host = _ms.getHostBy(vm.getHostId());
if(host == null) {
s_logger.warn("VM " + vmId + "'s host does not exist, sending blank response for console access request");
sendResponse(resp, "");
return;
}
String rootUrl = _ms.getConsoleAccessUrlRoot(vmId);
if(rootUrl == null) {
sendResponse(resp, "<html><body><p>Console access will be ready in a few minutes. Please try it again later.</p></body></html>");
return;
}
String vmName = vm.getHostName();
if(vm.getType() == VirtualMachine.Type.User) {
UserVm userVm = (UserVm)_vmMgr.findByIdAndType(VirtualMachine.Type.User, vmId);
String displayName = userVm.getDisplayName();
if(displayName != null && !displayName.isEmpty() && !displayName.equals(vmName)) {
vmName += "(" + displayName + ")";
}
}
StringBuffer sb = new StringBuffer();
sb.append("<html><title>").append(escapeHTML(vmName)).append("</title><frameset><frame src=\"").append(composeConsoleAccessUrl(rootUrl, vm, host));
sb.append("\"></frame></frameset></html>");
s_logger.debug("the console url is :: " + sb.toString());
sendResponse(resp, sb.toString());
}
private void handleAuthRequest(HttpServletRequest req, HttpServletResponse resp, long vmId) {
// TODO authentication channel between console proxy VM and management server needs to be secured,
// the data is now being sent through private network, but this is apparently not enough
VMInstanceVO vm = _vmMgr.findById(vmId);
if(vm == null) {
s_logger.warn("VM " + vmId + " does not exist, sending failed response for authentication request from console proxy");
sendResponse(resp, "failed");
return;
}
if(vm.getHostId() == null) {
s_logger.warn("VM " + vmId + " lost host info, failed response for authentication request from console proxy");
sendResponse(resp, "failed");
return;
}
HostVO host = _ms.getHostBy(vm.getHostId());
if(host == null) {
s_logger.warn("VM " + vmId + "'s host does not exist, sending failed response for authentication request from console proxy");
sendResponse(resp, "failed");
return;
}
String sid = req.getParameter("sid");
if(sid == null || !sid.equals(vm.getVncPassword())) {
s_logger.warn("sid " + sid + " in url does not match stored sid " + vm.getVncPassword());
sendResponse(resp, "failed");
return;
}
sendResponse(resp, "success");
}
// put the ugly stuff here
static public Ternary<String, String, String> parseHostInfo(String hostInfo) {
String host = null;
String tunnelUrl = null;
String tunnelSession = null;
s_logger.info("Parse host info returned from executing GetVNCPortCommand. host info: " + hostInfo);
if(hostInfo != null && hostInfo.startsWith("consoleurl")) {
String tokens[] = hostInfo.split("&");
if(hostInfo.length() > 19 && hostInfo.indexOf('/', 19) > 19) {
host = hostInfo.substring(19, hostInfo.indexOf('/', 19)).trim();
tunnelUrl = tokens[0].substring("consoleurl=".length());
tunnelSession = tokens[1].split("=")[1];
} else {
host = "";
}
} else {
host = hostInfo;
}
}
private void handleAccessRequest(HttpServletRequest req, HttpServletResponse resp, long vmId) {
VMInstanceVO vm = _vmMgr.findById(vmId);
if(vm == null) {
s_logger.warn("VM " + vmId + " does not exist, sending blank response for console access request");
sendResponse(resp, "");
return;
}
if(vm.getHostId() == null) {
s_logger.warn("VM " + vmId + " lost host info, sending blank response for console access request");
sendResponse(resp, "");
return;
}
HostVO host = _ms.getHostBy(vm.getHostId());
if(host == null) {
s_logger.warn("VM " + vmId + "'s host does not exist, sending blank response for console access request");
sendResponse(resp, "");
return;
}
String rootUrl = _ms.getConsoleAccessUrlRoot(vmId);
if(rootUrl == null) {
sendResponse(resp, "<html><body><p>Console access will be ready in a few minutes. Please try it again later.</p></body></html>");
return;
}
String vmName = vm.getHostName();
if(vm.getType() == VirtualMachine.Type.User) {
UserVm userVm = (UserVm)_vmMgr.findByIdAndType(VirtualMachine.Type.User, vmId);
String displayName = userVm.getDisplayName();
if(displayName != null && !displayName.isEmpty() && !displayName.equals(vmName)) {
vmName += "(" + displayName + ")";
}
}
StringBuffer sb = new StringBuffer();
sb.append("<html><title>").append(escapeHTML(vmName)).append("</title><frameset><frame src=\"").append(composeConsoleAccessUrl(rootUrl, vm, host));
sb.append("\"></frame></frameset></html>");
s_logger.debug("the console url is :: " + sb.toString());
sendResponse(resp, sb.toString());
}
private void handleAuthRequest(HttpServletRequest req, HttpServletResponse resp, long vmId) {
// TODO authentication channel between console proxy VM and management server needs to be secured,
// the data is now being sent through private network, but this is apparently not enough
VMInstanceVO vm = _vmMgr.findById(vmId);
if(vm == null) {
s_logger.warn("VM " + vmId + " does not exist, sending failed response for authentication request from console proxy");
sendResponse(resp, "failed");
return;
}
if(vm.getHostId() == null) {
s_logger.warn("VM " + vmId + " lost host info, failed response for authentication request from console proxy");
sendResponse(resp, "failed");
return;
}
HostVO host = _ms.getHostBy(vm.getHostId());
if(host == null) {
s_logger.warn("VM " + vmId + "'s host does not exist, sending failed response for authentication request from console proxy");
sendResponse(resp, "failed");
return;
}
String sid = req.getParameter("sid");
if(sid == null || !sid.equals(vm.getVncPassword())) {
s_logger.warn("sid " + sid + " in url does not match stored sid " + vm.getVncPassword());
sendResponse(resp, "failed");
return;
}
sendResponse(resp, "success");
}
// put the ugly stuff here
static public Ternary<String, String, String> parseHostInfo(String hostInfo) {
String host = null;
String tunnelUrl = null;
String tunnelSession = null;
s_logger.info("Parse host info returned from executing GetVNCPortCommand. host info: " + hostInfo);
if(hostInfo != null && hostInfo.startsWith("consoleurl")) {
String tokens[] = hostInfo.split("&");
if(hostInfo.length() > 19 && hostInfo.indexOf('/', 19) > 19) {
host = hostInfo.substring(19, hostInfo.indexOf('/', 19)).trim();
tunnelUrl = tokens[0].substring("consoleurl=".length());
tunnelSession = tokens[1].split("=")[1];
} else {
host = "";
}
} else {
host = hostInfo;
}
return new Ternary<String, String, String>(host, tunnelUrl, tunnelSession);
}
private String composeThumbnailUrl(String rootUrl, VMInstanceVO vm, HostVO hostVo, int w, int h) {
StringBuffer sb = new StringBuffer(rootUrl);
}
String host = hostVo.getPrivateIpAddress();
Pair<String, Integer> portInfo = _ms.getVncPort(vm);
Ternary<String, String, String> parsedHostInfo = parseHostInfo(portInfo.first());
String sid = vm.getVncPassword();
String tag = String.valueOf(vm.getId());
tag = _identityService.getIdentityUuid("vm_instance", tag);
String ticket = genAccessTicket(host, String.valueOf(portInfo.second()), sid, tag);
private String composeThumbnailUrl(String rootUrl, VMInstanceVO vm, HostVO hostVo, int w, int h) {
StringBuffer sb = new StringBuffer(rootUrl);
ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(_ms.getHashKey());
ConsoleProxyClientParam param = new ConsoleProxyClientParam();
param.setClientHostAddress(parsedHostInfo.first());
param.setClientHostPort(portInfo.second());
param.setClientHostPassword(sid);
param.setClientTag(tag);
param.setTicket(ticket);
if(parsedHostInfo.second() != null && parsedHostInfo.third() != null) {
param.setClientTunnelUrl(parsedHostInfo.second());
param.setClientTunnelSession(parsedHostInfo.third());
}
sb.append("/ajax?token=" + encryptor.encryptObject(ConsoleProxyClientParam.class, param));
sb.append("&w=").append(w).append("&h=").append(h);
if(s_logger.isDebugEnabled()) {
String host = hostVo.getPrivateIpAddress();
Pair<String, Integer> portInfo = _ms.getVncPort(vm);
Ternary<String, String, String> parsedHostInfo = parseHostInfo(portInfo.first());
String sid = vm.getVncPassword();
String tag = String.valueOf(vm.getId());
tag = _identityService.getIdentityUuid("vm_instance", tag);
String ticket = genAccessTicket(host, String.valueOf(portInfo.second()), sid, tag);
ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(_ms.getHashKey());
ConsoleProxyClientParam param = new ConsoleProxyClientParam();
param.setClientHostAddress(parsedHostInfo.first());
param.setClientHostPort(portInfo.second());
param.setClientHostPassword(sid);
param.setClientTag(tag);
param.setTicket(ticket);
if(parsedHostInfo.second() != null && parsedHostInfo.third() != null) {
param.setClientTunnelUrl(parsedHostInfo.second());
param.setClientTunnelSession(parsedHostInfo.third());
}
sb.append("/ajax?token=" + encryptor.encryptObject(ConsoleProxyClientParam.class, param));
sb.append("&w=").append(w).append("&h=").append(h);
if(s_logger.isDebugEnabled()) {
s_logger.debug("Compose thumbnail url: " + sb.toString());
}
return sb.toString();
}
private String composeConsoleAccessUrl(String rootUrl, VMInstanceVO vm, HostVO hostVo) {
StringBuffer sb = new StringBuffer(rootUrl);
String host = hostVo.getPrivateIpAddress();
Pair<String, Integer> portInfo = _ms.getVncPort(vm);
if(s_logger.isDebugEnabled())
s_logger.debug("Port info " + portInfo.first());
return sb.toString();
}
Ternary<String, String, String> parsedHostInfo = parseHostInfo(portInfo.first());
private String composeConsoleAccessUrl(String rootUrl, VMInstanceVO vm, HostVO hostVo) {
StringBuffer sb = new StringBuffer(rootUrl);
String host = hostVo.getPrivateIpAddress();
String sid = vm.getVncPassword();
String tag = String.valueOf(vm.getId());
tag = _identityService.getIdentityUuid("vm_instance", tag);
String ticket = genAccessTicket(host, String.valueOf(portInfo.second()), sid, tag);
ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(_ms.getHashKey());
ConsoleProxyClientParam param = new ConsoleProxyClientParam();
param.setClientHostAddress(parsedHostInfo.first());
param.setClientHostPort(portInfo.second());
param.setClientHostPassword(sid);
param.setClientTag(tag);
param.setTicket(ticket);
if(parsedHostInfo.second() != null && parsedHostInfo.third() != null) {
param.setClientTunnelUrl(parsedHostInfo.second());
param.setClientTunnelSession(parsedHostInfo.third());
}
sb.append("/ajax?token=" + encryptor.encryptObject(ConsoleProxyClientParam.class, param));
// for console access, we need guest OS type to help implement keyboard
long guestOs = vm.getGuestOSId();
GuestOSVO guestOsVo = _ms.getGuestOs(guestOs);
if(guestOsVo.getCategoryId() == 6)
sb.append("&guest=windows");
if(s_logger.isDebugEnabled()) {
Pair<String, Integer> portInfo = _ms.getVncPort(vm);
if(s_logger.isDebugEnabled())
s_logger.debug("Port info " + portInfo.first());
Ternary<String, String, String> parsedHostInfo = parseHostInfo(portInfo.first());
String sid = vm.getVncPassword();
String tag = String.valueOf(vm.getId());
tag = _identityService.getIdentityUuid("vm_instance", tag);
String ticket = genAccessTicket(host, String.valueOf(portInfo.second()), sid, tag);
ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(_ms.getHashKey());
ConsoleProxyClientParam param = new ConsoleProxyClientParam();
param.setClientHostAddress(parsedHostInfo.first());
param.setClientHostPort(portInfo.second());
param.setClientHostPassword(sid);
param.setClientTag(tag);
param.setTicket(ticket);
if(parsedHostInfo.second() != null && parsedHostInfo.third() != null) {
param.setClientTunnelUrl(parsedHostInfo.second());
param.setClientTunnelSession(parsedHostInfo.third());
}
sb.append("/ajax?token=" + encryptor.encryptObject(ConsoleProxyClientParam.class, param));
// for console access, we need guest OS type to help implement keyboard
long guestOs = vm.getGuestOSId();
GuestOSVO guestOsVo = _ms.getGuestOs(guestOs);
if(guestOsVo.getCategoryId() == 6)
sb.append("&guest=windows");
if(s_logger.isDebugEnabled()) {
s_logger.debug("Compose console url: " + sb.toString());
}
return sb.toString();
}
public static String genAccessTicket(String host, String port, String sid, String tag) {
return genAccessTicket(host, port, sid, tag, new Date());
}
public static String genAccessTicket(String host, String port, String sid, String tag, Date normalizedHashTime) {
String params = "host=" + host + "&port=" + port + "&sid=" + sid + "&tag=" + tag;
try {
Mac mac = Mac.getInstance("HmacSHA1");
long ts = normalizedHashTime.getTime();
ts = ts/60000; // round up to 1 minute
String secretKey = _ms.getHashKey();
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
mac.init(keySpec);
mac.update(params.getBytes());
mac.update(String.valueOf(ts).getBytes());
byte[] encryptedBytes = mac.doFinal();
return Base64.encodeBase64URLSafeString(encryptedBytes);
} catch(Exception e) {
s_logger.error("Unexpected exception ", e);
}
return "";
}
private void sendResponse(HttpServletResponse resp, String content) {
try {
resp.setContentType("text/html");
resp.getWriter().print(content);
} catch(IOException e) {
if(s_logger.isInfoEnabled()) {
return sb.toString();
}
public static String genAccessTicket(String host, String port, String sid, String tag) {
return genAccessTicket(host, port, sid, tag, new Date());
}
public static String genAccessTicket(String host, String port, String sid, String tag, Date normalizedHashTime) {
String params = "host=" + host + "&port=" + port + "&sid=" + sid + "&tag=" + tag;
try {
Mac mac = Mac.getInstance("HmacSHA1");
long ts = normalizedHashTime.getTime();
ts = ts/60000; // round up to 1 minute
String secretKey = _ms.getHashKey();
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
mac.init(keySpec);
mac.update(params.getBytes());
mac.update(String.valueOf(ts).getBytes());
byte[] encryptedBytes = mac.doFinal();
return Base64.encodeBase64URLSafeString(encryptedBytes);
} catch(Exception e) {
s_logger.error("Unexpected exception ", e);
}
return "";
}
private void sendResponse(HttpServletResponse resp, String content) {
try {
resp.setContentType("text/html");
resp.getWriter().print(content);
} catch(IOException e) {
if(s_logger.isInfoEnabled()) {
s_logger.info("Client may already close the connection");
}
}
}
private boolean checkSessionPermision(HttpServletRequest req, long vmId, Account accountObj) {
}
}
private boolean checkSessionPermision(HttpServletRequest req, long vmId, Account accountObj) {
VMInstanceVO vm = _vmMgr.findById(vmId);
if(vm == null) {
s_logger.debug("Console/thumbnail access denied. VM " + vmId + " does not exist in system any more");
return false;
s_logger.debug("Console/thumbnail access denied. VM " + vmId + " does not exist in system any more");
return false;
}
// root admin can access anything
if(accountObj.getType() == Account.ACCOUNT_TYPE_ADMIN)
return true;
if(accountObj.getType() == Account.ACCOUNT_TYPE_ADMIN)
return true;
switch(vm.getType())
{
case User :
try {
_accountMgr.checkAccess(accountObj, null, true, vm);
} catch (PermissionDeniedException ex) {
if (accountObj.getType() == Account.ACCOUNT_TYPE_NORMAL) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("VM access is denied. VM owner account " + vm.getAccountId()
+ " does not match the account id in session " + accountObj.getId() + " and caller is a normal user");
}
} else if(accountObj.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || accountObj.getType() == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN) {
if(s_logger.isDebugEnabled()) {
s_logger.debug("VM access is denied. VM owner account " + vm.getAccountId()
+ " does not match the account id in session " + accountObj.getId() + " and the domain-admin caller does not manage the target domain");
}
}
return false;
}
break;
try {
_accountMgr.checkAccess(accountObj, null, true, vm);
} catch (PermissionDeniedException ex) {
if (accountObj.getType() == Account.ACCOUNT_TYPE_NORMAL) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("VM access is denied. VM owner account " + vm.getAccountId()
+ " does not match the account id in session " + accountObj.getId() + " and caller is a normal user");
}
} else if(accountObj.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || accountObj.getType() == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN) {
if(s_logger.isDebugEnabled()) {
s_logger.debug("VM access is denied. VM owner account " + vm.getAccountId()
+ " does not match the account id in session " + accountObj.getId() + " and the domain-admin caller does not manage the target domain");
}
}
return false;
}
break;
case DomainRouter:
case ConsoleProxy :
case SecondaryStorageVm:
return false;
default :
s_logger.warn("Unrecoginized virtual machine type, deny access by default. type: " + vm.getType());
return false;
return false;
default :
s_logger.warn("Unrecoginized virtual machine type, deny access by default. type: " + vm.getType());
return false;
}
return true;
}
private boolean isValidCmd(String cmd) {
if(cmd.equalsIgnoreCase("thumbnail") || cmd.equalsIgnoreCase("access") || cmd.equalsIgnoreCase("auth")) {
return true;
}
private boolean isValidCmd(String cmd) {
if(cmd.equalsIgnoreCase("thumbnail") || cmd.equalsIgnoreCase("access") || cmd.equalsIgnoreCase("auth")) {
return true;
}
return false;
}
public boolean verifyUser(Long userId) {
// copy from ApiServer.java, a bit ugly here
User user = _accountMgr.getUserIncludingRemoved(userId);
Account account = null;
if (user != null) {
account = _accountMgr.getAccount(user.getAccountId());
}
if ((user == null) || (user.getRemoved() != null) || !user.getState().equals(Account.State.enabled)
|| (account == null) || !account.getState().equals(Account.State.enabled)) {
s_logger.warn("Deleted/Disabled/Locked user with id=" + userId + " attempting to access public API");
return false;
}
return true;
return false;
}
// copied and modified from ApiServer.java.
public boolean verifyUser(Long userId) {
// copy from ApiServer.java, a bit ugly here
User user = _accountMgr.getUserIncludingRemoved(userId);
Account account = null;
if (user != null) {
account = _accountMgr.getAccount(user.getAccountId());
}
if ((user == null) || (user.getRemoved() != null) || !user.getState().equals(Account.State.enabled)
|| (account == null) || !account.getState().equals(Account.State.enabled)) {
s_logger.warn("Deleted/Disabled/Locked user with id=" + userId + " attempting to access public API");
return false;
}
return true;
}
// copied and modified from ApiServer.java.
// TODO need to replace the whole servlet with a API command
private boolean verifyRequest(Map<String, Object[]> requestParameters) {
try {
@ -516,7 +516,7 @@ public class ConsoleProxyServlet extends HttpServlet {
for (String paramName : parameterNames) {
// parameters come as name/value pairs in the form String/String[]
String paramValue = ((String[])requestParameters.get(paramName))[0];
if ("signature".equalsIgnoreCase(paramName)) {
signature = paramValue;
} else {
@ -531,7 +531,7 @@ public class ConsoleProxyServlet extends HttpServlet {
}
}
}
// if api/secret key are passed to the parameters
if ((signature == null) || (apiKey == null)) {
@ -573,16 +573,16 @@ public class ConsoleProxyServlet extends HttpServlet {
mac.init(keySpec);
mac.update(unsignedRequest.getBytes());
byte[] encryptedBytes = mac.doFinal();
String computedSignature = com.cloud.utils.encoding.Base64.encodeBytes(encryptedBytes);
String computedSignature = Base64.encodeBase64URLSafeString(encryptedBytes);
boolean equalSig = signature.equals(computedSignature);
if (!equalSig) {
s_logger.debug("User signature: " + signature + " is not equaled to computed signature: " + computedSignature);
s_logger.debug("User signature: " + signature + " is not equaled to computed signature: " + computedSignature);
}
if(equalSig) {
requestParameters.put("userid", new Object[] {String.valueOf(user.getId())});
requestParameters.put("account", new Object[] {account.getAccountName()});
requestParameters.put("accountobj", new Object[] { account });
requestParameters.put("userid", new Object[] {String.valueOf(user.getId())});
requestParameters.put("account", new Object[] {account.getAccountName()});
requestParameters.put("accountobj", new Object[] { account });
}
return equalSig;
} catch (Exception ex) {
@ -590,23 +590,23 @@ public class ConsoleProxyServlet extends HttpServlet {
}
return false;
}
public static final String escapeHTML(String content){
if(content == null || content.isEmpty())
return content;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < content.length(); i++) {
char c = content.charAt(i);
switch (c) {
case '<': sb.append("&lt;"); break;
case '>': sb.append("&gt;"); break;
case '&': sb.append("&amp;"); break;
case '"': sb.append("&quot;"); break;
case ' ': sb.append("&nbsp;");break;
default: sb.append(c); break;
}
char c = content.charAt(i);
switch (c) {
case '<': sb.append("&lt;"); break;
case '>': sb.append("&gt;"); break;
case '&': sb.append("&amp;"); break;
case '"': sb.append("&quot;"); break;
case ' ': sb.append("&nbsp;");break;
default: sb.append(c); break;
}
}
return sb.toString();
}
}
}

View File

@ -31,10 +31,9 @@ import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import com.cloud.utils.encoding.Base64;
/**
*
*
*
*
*

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,6 @@ import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.cloud.utils.encoding.Base64;
import com.cloud.utils.exception.CloudRuntimeException;
import com.trilead.ssh2.ChannelCondition;
import com.trilead.ssh2.Connection;
@ -182,7 +181,7 @@ public class TestClientWithAPI {
if (arg.equals("-no")) {
networkOfferingId = iter.next();
}
if (arg.equals("-pass")) {
vmPassword = iter.next();
}
@ -210,6 +209,7 @@ public class TestClientWithAPI {
for (int i = 0; i < numThreads; i++) {
new Thread(new Runnable() {
@Override
public void run() {
do {
String username = null;
@ -440,7 +440,7 @@ public class TestClientWithAPI {
for (int j = 0; j < childNodes.getLength(); j++) {
Node n = childNodes.item(j);
if ("id".equals(n.getNodeName())) {
// if ("ipaddress".equals(n.getNodeName())) {
// if ("ipaddress".equals(n.getNodeName())) {
ipAddress = n.getTextContent();
} else if ("issourcenat".equals(n.getNodeName())) {
isSourceNat = Boolean.parseBoolean(n.getTextContent());
@ -478,7 +478,7 @@ public class TestClientWithAPI {
}
else if("ipaddress".equals(n.getNodeName()))
{
ipAddress = n.getTextContent();
ipAddress = n.getTextContent();
}
else if ("issourcenat".equals(n.getNodeName())) {
isSourceNat = Boolean.parseBoolean(n.getTextContent());
@ -609,7 +609,7 @@ public class TestClientWithAPI {
s_logger.error("Create virtual network failed for account " + username + " with error code :" + responseCode + ", aborting deployment test. The command was sent with url " + url);
return -1;
}
/*
/*
// ---------------------------------
// CREATE DIRECT NETWORK
// ---------------------------------
@ -629,9 +629,9 @@ public class TestClientWithAPI {
s_logger.error("Create direct network failed for account " + username + " with error code :" + responseCode + ", aborting deployment test. The command was sent with url " + url);
return -1;
}
*/
*/
// ---------------------------------
// DEPLOY LINUX VM
// ---------------------------------
@ -706,7 +706,7 @@ public class TestClientWithAPI {
}
else
{
s_logger.info("Associate IP Address response code: " + responseCode);
s_logger.info("Associate IP Address response code: " + responseCode);
long publicIpId = Long.parseLong(values.get("id"));
s_logger.info("Associate IP's Id: " + publicIpId);
_publicIpId.set(values.get("id"));
@ -715,13 +715,13 @@ public class TestClientWithAPI {
s_logger.error("associate ip address for windows vm failed with error code: " + responseCode + ". Following URL was sent: " + url);
return responseCode;
}
String encodedPublicIpId = URLEncoder.encode(_publicIpId.get(), "UTF-8");
requestToSign = "apikey=" + encodedApiKey + "&command=listPublicIpAddresses"+"&id="+ encodedPublicIpId;
requestToSign = requestToSign.toLowerCase();
signature = signRequest(requestToSign, _secretKey.get());
encodedSignature = URLEncoder.encode(signature, "UTF-8");
url = developerServer + "?command=listPublicIpAddresses&apikey=" + encodedApiKey + "&id=" + encodedPublicIpId + "&signature=" + encodedSignature;
client = new HttpClient();
method = new GetMethod(url);
@ -730,9 +730,9 @@ public class TestClientWithAPI {
s_logger.info("list ip addresses for user " + userId + " response code: " + responseCode);
if (responseCode == 200) {
InputStream is = method.getResponseBodyAsStream();
// InputStream ips = method.getResponseBodyAsStream();
// InputStream ips = method.getResponseBodyAsStream();
List<String> ipAddressValues = getIPs(is, false);
// List<String> ipAddressVals = getIPs(is, false, true);
// List<String> ipAddressVals = getIPs(is, false, true);
if ((ipAddressValues != null) && !ipAddressValues.isEmpty()) {
_windowsIpId.set(ipAddressValues.get(0));
_windowsIP.set(ipAddressValues.get(1));
@ -743,7 +743,7 @@ public class TestClientWithAPI {
s_logger.error("list ip addresses failed with error code: " + responseCode + ". Following URL was sent: " + url);
return responseCode;
}
// ---------------------------------
// Use the SourceNat IP for linux
// ---------------------------------
@ -776,17 +776,17 @@ public class TestClientWithAPI {
return responseCode;
}
}
//--------------------------------------------
// Enable Static NAT for the Source NAT Ip
//--------------------------------------------
String encodedSourceNatPublicIpId = URLEncoder.encode(_linuxIpId.get(), "UTF-8");
/* requestToSign = "apikey=" + encodedApiKey + "&command=enableStaticNat"+"&id=" + encodedSourceNatPublicIpId + "&virtualMachineId=" + encodedVmId;;
/* requestToSign = "apikey=" + encodedApiKey + "&command=enableStaticNat"+"&id=" + encodedSourceNatPublicIpId + "&virtualMachineId=" + encodedVmId;;
requestToSign = requestToSign.toLowerCase();
signature = signRequest(requestToSign, _secretKey.get());
encodedSignature = URLEncoder.encode(signature, "UTF-8");
url = developerServer + "?command=enableStaticNat&apikey=" + encodedApiKey + "&signature=" + encodedSignature + "&id=" + encodedSourceNatPublicIpId + "&virtualMachineId=" + encodedVmId;
client = new HttpClient();
method = new GetMethod(url);
@ -801,7 +801,7 @@ public class TestClientWithAPI {
s_logger.error("Enable Static NAT failed with error code: " + responseCode + ". Following URL was sent: " + url);
return responseCode;
}
*/
*/
// -------------------------------------------------------------
// CREATE IP FORWARDING RULE -- Linux VM
// -------------------------------------------------------------
@ -825,7 +825,7 @@ public class TestClientWithAPI {
long ipfwdid = Long.parseLong(values.get("id"));
s_logger.info("got Port Forwarding Rule's Id:" + ipfwdid);
_linipfwdid.set(values.get("id"));
} else {
s_logger.error("Port forwarding rule creation failed with error code: " + responseCode + ". Following URL was sent: " + url);
return responseCode;
@ -882,7 +882,7 @@ public class TestClientWithAPI {
String encodedTemplateId = URLEncoder.encode("" + templateId, "UTF-8");
encodedApiKey = URLEncoder.encode(_apiKey.get(), "UTF-8");
String encodedNetworkIds = URLEncoder.encode(_networkId.get()+",206","UTF-8");
requestToSign = "apikey=" + encodedApiKey + "&command=deployVirtualMachine&diskofferingid=" + diskOfferingId + "&networkids=" + encodedNetworkIds + "&serviceofferingid=" + encodedServiceOfferingId + "&templateid=" + encodedTemplateId
+ "&zoneid=" + encodedZoneId;
requestToSign = requestToSign.toLowerCase();
@ -918,14 +918,14 @@ public class TestClientWithAPI {
//--------------------------------------------
// Enable Static NAT for the Non Source NAT Ip
//--------------------------------------------
encodedVmId = URLEncoder.encode(_windowsVmId.get(), "UTF-8");
encodedPublicIpId = URLEncoder.encode(_publicIpId.get(), "UTF-8");
requestToSign = "apikey=" + encodedApiKey + "&command=enableStaticNat"+"&ipaddressid="+ encodedPublicIpId + "&virtualMachineId=" + encodedVmId;
requestToSign = requestToSign.toLowerCase();
signature = signRequest(requestToSign, _secretKey.get());
encodedSignature = URLEncoder.encode(signature, "UTF-8");
url = developerServer + "?command=enableStaticNat&apikey=" + encodedApiKey + "&ipaddressid=" + encodedPublicIpId + "&signature=" + encodedSignature + "&virtualMachineId=" + encodedVmId;
client = new HttpClient();
method = new GetMethod(url);
@ -941,7 +941,7 @@ public class TestClientWithAPI {
return responseCode;
}
// -------------------------------------------------------------
// CREATE IP FORWARDING RULE -- Windows VM
// -------------------------------------------------------------
@ -972,7 +972,7 @@ public class TestClientWithAPI {
s_logger.error("Port forwarding rule creation failed with error code: " + responseCode + ". Following URL was sent: " + url);
return responseCode;
}
}
}
}
return responseCode;
}
@ -1178,7 +1178,7 @@ public class TestClientWithAPI {
}
// Create volume from the snapshot created on the previous step and attach it to the running vm
/* encodedApiKey = URLEncoder.encode(_apiKey.get(), "UTF-8");
/* encodedApiKey = URLEncoder.encode(_apiKey.get(), "UTF-8");
requestToSign = "apikey=" + encodedApiKey + "&command=createVolume&name=" + _account.get() + "&snapshotid=" + _snapshot.get();
requestToSign = requestToSign.toLowerCase();
signature = signRequest(requestToSign, _secretKey.get());
@ -1222,7 +1222,7 @@ public class TestClientWithAPI {
return responseCode;
}
}
*/
*/
// -----------------------------
// Execute reboot/stop/start commands for the VMs before deleting the account - made to exercise xen
// -----------------------------
@ -1896,7 +1896,7 @@ public class TestClientWithAPI {
InputStream input = method.getResponseBodyAsStream();
Element el = queryAsyncJobResult(server, input);
s_logger.info("IP forwarding rule was successfully deleted");
} else {
s_logger.error("IP forwarding rule creation failed with error code: " + responseCode + ". Following URL was sent: " + url);
return responseCode;
@ -1911,7 +1911,7 @@ public class TestClientWithAPI {
requestToSign = requestToSign.toLowerCase();
signature = signRequest(requestToSign, _secretKey.get());
encodedSignature = URLEncoder.encode(signature, "UTF-8");
url = developerServer + "?command=disableStaticNat&apikey=" + encodedApiKey + "&id=" + encodedPublicIpId + "&signature=" + encodedSignature ;
client = new HttpClient();
method = new GetMethod(url);
@ -1926,7 +1926,7 @@ public class TestClientWithAPI {
s_logger.error("Disable Static NAT failed with error code: " + responseCode + ". Following URL was sent: " + url);
return responseCode;
}
// -----------------------------------------
// DISASSOCIATE IP ADDRESSES
// -----------------------------------------
@ -1946,7 +1946,7 @@ public class TestClientWithAPI {
InputStream input = method.getResponseBodyAsStream();
Element disassocipel = queryAsyncJobResult(server, input);
Map<String, String> success = getSingleValueFromXML(disassocipel, new String[] {"success"});
// Map<String, String> success = getSingleValueFromXML(input, new String[] { "success" });
// Map<String, String> success = getSingleValueFromXML(input, new String[] { "success" });
s_logger.info("disassociate ip address..success? " + success.get("success"));
} else {
s_logger.error("disassociate ip address failed with error code: " + responseCode + ". Following URL was sent: " + url);
@ -1977,7 +1977,7 @@ public class TestClientWithAPI {
mac.init(keySpec);
mac.update(request.getBytes());
byte[] encryptedBytes = mac.doFinal();
return Base64.encodeBytes(encryptedBytes);
return org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(encryptedBytes);
} catch (Exception ex) {
s_logger.error("unable to sign request", ex);
}

View File

@ -30,208 +30,208 @@ import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.codec.binary.Base64;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.cloud.utils.encoding.Base64;
import com.cloud.utils.exception.CloudRuntimeException;
public class UtilsForTest {
private static DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
public static boolean verifyTags (Map<String, String> params) {
boolean result = true;
for (String value : params.keySet()) {
if (params.get(value) == null) {
result=false;
}
}
return result;
}
public static boolean verifyTagValues (Map<String, String> params, Map<String, String> pattern) {
boolean result = true;
if (pattern != null) {
for (String value : pattern.keySet()) {
if (!pattern.get(value).equals(params.get(value))) {
result=false;
System.out.println("Tag " + value + " has " + params.get(value) + " while expected value is: " + pattern.get(value));
}
}
}
return result;
}
public static Map<String, String> parseXML(InputStream is,
String[] tagNames) {
Map<String, String> returnValues = new HashMap<String, String>();
try {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(is);
Element rootElement = doc.getDocumentElement();
for (int i = 0; i < tagNames.length; i++) {
NodeList targetNodes = rootElement
.getElementsByTagName(tagNames[i]);
if (targetNodes.getLength() <= 0) {
System.out.println("no " + tagNames[i]
+ " tag in the response");
returnValues.put(tagNames[i], null);
} else {
returnValues.put(tagNames[i], targetNodes.item(0)
.getTextContent());
}
}
} catch (Exception ex) {
System.out.println("error processing XML");
ex.printStackTrace();
}
return returnValues;
}
public static ArrayList<HashMap<String, String>> parseMulXML (InputStream is, String[] tagNames){
ArrayList<HashMap<String, String>> returnValues = new ArrayList<HashMap <String, String>>();
try {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(is);
Element rootElement = doc.getDocumentElement();
for (int i = 0; i < tagNames.length; i++) {
NodeList targetNodes = rootElement
.getElementsByTagName(tagNames[i]);
if (targetNodes.getLength() <= 0) {
System.out.println("no " + tagNames[i]
+ " tag in XML response...returning null");
} else {
for (int j = 0; j < targetNodes.getLength(); j++) {
HashMap<String, String> valueList = new HashMap<String,String> ();
Node node = targetNodes.item(j);
//parse child nodes
NodeList child = node.getChildNodes();
for (int c=0; c<node.getChildNodes().getLength(); c++){
child.item(c).getNodeName();
valueList.put(child.item(c).getNodeName(), child.item(c).getTextContent());
}
returnValues.add(valueList);
}
}
}
} catch (Exception ex) {
System.out.println(ex);
}
return returnValues;
}
public static String createMD5String(String password) {
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new CloudRuntimeException("Error", e);
}
private static DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
md5.reset();
BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
public static boolean verifyTags (Map<String, String> params) {
boolean result = true;
for (String value : params.keySet()) {
if (params.get(value) == null) {
result=false;
}
}
return result;
}
// make sure our MD5 hash value is 32 digits long...
StringBuffer sb = new StringBuffer();
String pwStr = pwInt.toString(16);
int padding = 32 - pwStr.length();
for (int i = 0; i < padding; i++) {
sb.append('0');
}
sb.append(pwStr);
return sb.toString();
}
public static Map<String, String> getSingleValueFromXML(InputStream is,
String[] tagNames) {
Map<String, String> returnValues = new HashMap<String, String>();
try {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(is);
Element rootElement = doc.getDocumentElement();
public static boolean verifyTagValues (Map<String, String> params, Map<String, String> pattern) {
boolean result = true;
if (pattern != null) {
for (String value : pattern.keySet()) {
if (!pattern.get(value).equals(params.get(value))) {
result=false;
System.out.println("Tag " + value + " has " + params.get(value) + " while expected value is: " + pattern.get(value));
}
}
}
return result;
}
public static Map<String, String> parseXML(InputStream is,
String[] tagNames) {
Map<String, String> returnValues = new HashMap<String, String>();
try {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(is);
Element rootElement = doc.getDocumentElement();
for (int i = 0; i < tagNames.length; i++) {
NodeList targetNodes = rootElement
.getElementsByTagName(tagNames[i]);
if (targetNodes.getLength() <= 0) {
System.out.println("no " + tagNames[i]
+ " tag in the response");
returnValues.put(tagNames[i], null);
} else {
returnValues.put(tagNames[i], targetNodes.item(0)
.getTextContent());
}
}
} catch (Exception ex) {
System.out.println("error processing XML");
ex.printStackTrace();
}
return returnValues;
}
public static ArrayList<HashMap<String, String>> parseMulXML (InputStream is, String[] tagNames){
ArrayList<HashMap<String, String>> returnValues = new ArrayList<HashMap <String, String>>();
try {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(is);
Element rootElement = doc.getDocumentElement();
for (int i = 0; i < tagNames.length; i++) {
NodeList targetNodes = rootElement
.getElementsByTagName(tagNames[i]);
if (targetNodes.getLength() <= 0) {
System.out.println("no " + tagNames[i]
+ " tag in XML response...returning null");
} else {
for (int j = 0; j < targetNodes.getLength(); j++) {
HashMap<String, String> valueList = new HashMap<String,String> ();
Node node = targetNodes.item(j);
//parse child nodes
NodeList child = node.getChildNodes();
for (int c=0; c<node.getChildNodes().getLength(); c++){
child.item(c).getNodeName();
valueList.put(child.item(c).getNodeName(), child.item(c).getTextContent());
}
returnValues.add(valueList);
}
}
}
} catch (Exception ex) {
System.out.println(ex);
}
return returnValues;
}
public static String createMD5String(String password) {
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new CloudRuntimeException("Error", e);
}
md5.reset();
BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
// make sure our MD5 hash value is 32 digits long...
StringBuffer sb = new StringBuffer();
String pwStr = pwInt.toString(16);
int padding = 32 - pwStr.length();
for (int i = 0; i < padding; i++) {
sb.append('0');
}
sb.append(pwStr);
return sb.toString();
}
public static Map<String, String> getSingleValueFromXML(InputStream is,
String[] tagNames) {
Map<String, String> returnValues = new HashMap<String, String>();
try {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(is);
Element rootElement = doc.getDocumentElement();
for (int i = 0; i < tagNames.length; i++) {
NodeList targetNodes = rootElement
.getElementsByTagName(tagNames[i]);
if (targetNodes.getLength() <= 0) {
System.out.println("no " + tagNames[i]
+ " tag in XML response...returning null");
} else {
returnValues.put(tagNames[i], targetNodes.item(0)
.getTextContent());
}
}
} catch (Exception ex) {
System.out.println("error processing XML");
ex.printStackTrace();
}
return returnValues;
}
public static Map<String, List<String>> getMultipleValuesFromXML(
InputStream is, String[] tagNames) {
Map<String, List<String>> returnValues = new HashMap<String, List<String>>();
try {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(is);
Element rootElement = doc.getDocumentElement();
for (int i = 0; i < tagNames.length; i++) {
NodeList targetNodes = rootElement
.getElementsByTagName(tagNames[i]);
if (targetNodes.getLength() <= 0) {
System.out.println("no " + tagNames[i]
+ " tag in XML response...returning null");
} else {
List<String> valueList = new ArrayList<String>();
for (int j = 0; j < targetNodes.getLength(); j++) {
Node node = targetNodes.item(j);
valueList.add(node.getTextContent());
}
returnValues.put(tagNames[i], valueList);
}
}
} catch (Exception ex) {
System.out.println(ex);
}
return returnValues;
}
public static String signRequest(String request, String key) {
try {
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(),
"HmacSHA1");
mac.init(keySpec);
mac.update(request.getBytes());
byte[] encryptedBytes = mac.doFinal();
//System.out.println("HmacSHA1 hash: " + encryptedBytes);
return Base64.encodeBase64URLSafeString(encryptedBytes);
} catch (Exception ex) {
System.out.println("unable to sign request");
ex.printStackTrace();
}
return null;
}
for (int i = 0; i < tagNames.length; i++) {
NodeList targetNodes = rootElement
.getElementsByTagName(tagNames[i]);
if (targetNodes.getLength() <= 0) {
System.out.println("no " + tagNames[i]
+ " tag in XML response...returning null");
} else {
returnValues.put(tagNames[i], targetNodes.item(0)
.getTextContent());
}
}
} catch (Exception ex) {
System.out.println("error processing XML");
ex.printStackTrace();
}
return returnValues;
}
public static Map<String, List<String>> getMultipleValuesFromXML(
InputStream is, String[] tagNames) {
Map<String, List<String>> returnValues = new HashMap<String, List<String>>();
try {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(is);
Element rootElement = doc.getDocumentElement();
for (int i = 0; i < tagNames.length; i++) {
NodeList targetNodes = rootElement
.getElementsByTagName(tagNames[i]);
if (targetNodes.getLength() <= 0) {
System.out.println("no " + tagNames[i]
+ " tag in XML response...returning null");
} else {
List<String> valueList = new ArrayList<String>();
for (int j = 0; j < targetNodes.getLength(); j++) {
Node node = targetNodes.item(j);
valueList.add(node.getTextContent());
}
returnValues.put(tagNames[i], valueList);
}
}
} catch (Exception ex) {
System.out.println(ex);
}
return returnValues;
}
public static String signRequest(String request, String key) {
try {
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(),
"HmacSHA1");
mac.init(keySpec);
mac.update(request.getBytes());
byte[] encryptedBytes = mac.doFinal();
//System.out.println("HmacSHA1 hash: " + encryptedBytes);
return Base64.encodeBytes(encryptedBytes);
} catch (Exception ex) {
System.out.println("unable to sign request");
ex.printStackTrace();
}
return null;
}
}

View File

@ -56,22 +56,18 @@ under the License.
<label for="username"><fmt:message key="label.username"/></label>
<input type="text" name="username" class="required" />
</div>
<!-- Password -->
<div class="field password">
<label for="password"><fmt:message key="label.password"/></label>
<input type="password" name="password" class="required" />
</div>
<!-- Domain -->
<div class="field domain">
<label for="domain"><fmt:message key="label.domain"/></label>
<input type="text" name="domain" />
</div>
<!-- Submit (login) -->
<input type="submit" value="<fmt:message key="label.login"/>" />
<!-- Select language -->
<div class="select-language">
<select name="language">
@ -84,7 +80,6 @@ under the License.
</div>
</form>
</div>
<!-- Instance wizard -->
<div class="multi-wizard instance-wizard">
<div class="progress">
@ -113,7 +108,6 @@ under the License.
</select>
</div>
</div>
<!-- Select template -->
<div class="section select-template">
<h3><fmt:message key="label.select.iso.or.template" /></h3>
@ -303,7 +297,6 @@ under the License.
</div>
</div>
</div>
<!-- Step 5c: Select security group -->
<div class="wizard-step-conditional select-security-group">
<div class="main-desc">
@ -315,7 +308,6 @@ under the License.
</div>
</div>
</div>
<!-- Step 6: Review -->
<div class="step review" wizard-step-id="review">
<div class="main-desc">
@ -332,7 +324,6 @@ under the License.
<input type="text" name="displayname" />
</div>
</div>
<!-- Add to group -->
<div class="select odd">
<div class="name">
@ -342,7 +333,6 @@ under the License.
<input type="text" name="groupname" />
</div>
</div>
<!-- Zone -->
<div class="select">
<div class="name">
@ -355,7 +345,6 @@ under the License.
<a href="1"><fmt:message key="label.edit"/></a>
</div>
</div>
<!-- Hypervisor -->
<div class="select odd">
<div class="name">
@ -368,7 +357,6 @@ under the License.
<a href="2"><fmt:message key="label.edit"/></a>
</div>
</div>
<!-- Template -->
<div class="select">
<div class="name">
@ -381,7 +369,6 @@ under the License.
<a href="2"><fmt:message key="label.edit"/></a>
</div>
</div>
<!-- Service offering -->
<div class="select odd">
<div class="name">
@ -394,7 +381,6 @@ under the License.
<a href="3"><fmt:message key="label.edit"/></a>
</div>
</div>
<!-- Data disk offering -->
<div class="select">
<div class="name">
@ -407,7 +393,6 @@ under the License.
<a href="4"><fmt:message key="label.edit"/></a>
</div>
</div>
<!-- Primary network -->
<div class="select odd">
<div class="name">
@ -438,7 +423,6 @@ under the License.
</div>
</div>
</form>
<!-- Computer diagram -->
<div class="diagram">
<div>
@ -451,7 +435,6 @@ under the License.
<div class="part hd"></div>
<div class="part network-card"></div>
</div>
<!-- Buttons -->
<div class="buttons">
<div class="button previous"><span><fmt:message key="label.previous"/></span></div>
@ -459,7 +442,6 @@ under the License.
<div class="button next"><span><fmt:message key="label.next"/></span></div>
</div>
</div>
<!-- Zone wizard -->
<div class="multi-wizard zone-wizard">
<div class="progress">
@ -505,7 +487,6 @@ under the License.
</div>
</form>
</div>
<!-- Step 2: Add zone -->
<div class="setup-zone" zone-wizard-form="zone"
zone-wizard-step-id="addZone">
@ -516,7 +497,6 @@ under the License.
<div class="select-container"></div>
</div>
</div>
<!-- Step 3.1: Setup Physical Network -->
<div class="setup-physical-network"
zone-wizard-step-id="setupPhysicalNetwork"
@ -535,7 +515,6 @@ under the License.
<fmt:message key="message.setup.physical.network.during.zone.creation.basic"/>
</div>
<div class="button add new-physical-network"><span class="icon">&nbsp;</span><span><fmt:message key="label.add.physical.network"/></span></div>
<!-- Traffic types drag area -->
<div class="traffic-types-drag-area">
<div class="header"><fmt:message key="label.traffic.types"/></div>
@ -610,13 +589,11 @@ under the License.
</li>
</ul>
</div>
<div class="drag-helper-icon"></div>
<div class="content input-area">
<form></form>
</div>
</div>
<!-- Step 3.1b: Add Netscaler device -->
<div class="setup-physical-network-basic"
zone-wizard-step-id="addNetscalerDevice"
@ -629,13 +606,11 @@ under the License.
<li class="guest-traffic"><fmt:message key="label.guest.traffic"/></li>
<li class="conditional storage-traffic"><fmt:message key="label.storage.traffic"/></li>
</ul>
<div class="info-desc"><fmt:message key="label.please.specify.netscaler.info"/></div>
<div class="content input-area">
<div class="select-container"></div>
</div>
</div>
<!-- Step 3.2: Configure public traffic -->
<div class="setup-public-traffic" zone-wizard-prefilter="addPublicNetwork"
zone-wizard-step-id="configurePublicTraffic">
@ -646,14 +621,12 @@ under the License.
<li class="guest-traffic"><fmt:message key="label.guest.traffic"/></li>
<li class="conditional storage-traffic"><fmt:message key="label.storage.traffic"/></li>
</ul>
<div class="info-desc" id="add_zone_public_traffic_desc">
<span id="for_basic_zone" style="display:none"><fmt:message key="message.public.traffic.in.basic.zone"/></span>
<span id="for_advanced_zone" style="display:none"><fmt:message key="message.public.traffic.in.advanced.zone"/></span>
</div>
<div ui-custom="publicTrafficIPRange"></div>
</div>
<!-- Step 3.3: Add pod -->
<div class="add-pod" zone-wizard-form="pod"
zone-wizard-step-id="addPod">
@ -664,7 +637,6 @@ under the License.
<li class="guest-traffic"><fmt:message key="label.guest.traffic"/></li>
<li class="conditional storage-traffic"><fmt:message key="label.storage.traffic"/></li>
</ul>
<div class="info-desc">
<fmt:message key="message.add.pod.during.zone.creation"/>
</div>
@ -672,7 +644,6 @@ under the License.
<div class="select-container"></div>
</div>
</div>
<!-- Step 3.4: Configure guest traffic -->
<div class="setup-guest-traffic"
zone-wizard-form="guestTraffic"
@ -685,7 +656,6 @@ under the License.
<li class="guest-traffic active"><fmt:message key="label.guest.traffic"/></li>
<li class="conditional storage-traffic"><fmt:message key="label.storage.traffic"/></li>
</ul>
<div class="info-desc" id="add_zone_guest_traffic_desc">
<span id="for_basic_zone" style="display:none"><fmt:message key="message.guest.traffic.in.basic.zone"/></span>
<span id="for_advanced_zone" style="display:none"><fmt:message key="message.guest.traffic.in.advanced.zone"/></span>
@ -694,7 +664,6 @@ under the License.
<div class="select-container"></div>
</div>
</div>
<!-- Step 3.5: Configure storage traffic -->
<div class="setup-storage-traffic" zone-wizard-prefilter="configureStorageTraffic"
zone-wizard-step-id="configureStorageTraffic">
@ -705,13 +674,11 @@ under the License.
<li class="guest-traffic"><fmt:message key="label.guest.traffic"/></li>
<li class="storage-traffic active"><fmt:message key="label.storage.traffic"/></li>
</ul>
<div class="info-desc">
<fmt:message key="message.storage.traffic"/>
</div>
<div ui-custom="storageTrafficIPRange"></div>
</div>
<!-- Step 4.1: Add cluster -->
<div class="add-cluster" zone-wizard-form="cluster"
zone-wizard-step-id="addCluster">
@ -729,7 +696,6 @@ under the License.
<div class="select-container"></div>
</div>
</div>
<!-- Step 4.2: Add host -->
<div class="add-cluster" zone-wizard-form="host"
zone-wizard-step-id="addHost" zone-wizard-prefilter="addHost">
@ -746,7 +712,6 @@ under the License.
<div class="select-container"></div>
</div>
</div>
<!-- Step 4.3: Add primary storage -->
<div class="add-cluster" zone-wizard-form="primaryStorage" zone-wizard-prefilter="addPrimaryStorage"
zone-wizard-step-id="addPrimaryStorage">
@ -763,7 +728,6 @@ under the License.
<div class="select-container"></div>
</div>
</div>
<!-- Step 4.4: Add secondary storage -->
<div class="add-cluster" zone-wizard-form="secondaryStorage"
zone-wizard-step-id="addSecondaryStorage">
@ -780,7 +744,6 @@ under the License.
<div class="select-container"></div>
</div>
</div>
<!-- Step 5: Launch -->
<div class="review" zone-wizard-step-id="launch">
<div class="main-desc pre-setup"><fmt:message key="message.launch.zone"/></div>
@ -794,7 +757,6 @@ under the License.
</div>
</div>
</div>
<!-- Buttons -->
<div class="buttons">
<div class="button previous"><span><fmt:message key="label.previous"/></span></div>
@ -802,7 +764,6 @@ under the License.
<div class="button next"><span><fmt:message key="label.next"/></span></div>
</div>
</div>
<!-- Network chart -->
<div class="network-chart normal">
<ul>
@ -820,7 +781,6 @@ under the License.
</li>
</ul>
</div>
<!-- Static NAT network chart -->
<div class="network-chart static-nat">
<ul>
@ -835,7 +795,6 @@ under the License.
</li>
</ul>
</div>
<!-- Project dashboard -->
<div class="project-dashboard-view">
<div class="overview-area">
@ -903,7 +862,6 @@ under the License.
</div>
</div>
</div>
<div class="info-boxes">
<!-- Networking and security -->
<div class="info-box networking-and-security">
@ -947,7 +905,6 @@ under the License.
</li>
</ul>
</div>
<!-- Events -->
<div class="info-box events">
<div class="title">
@ -966,7 +923,6 @@ under the License.
</div>
</div>
</div>
<!-- System dashboard -->
<div class="system-dashboard-view">
<div class="toolbar">

View File

@ -66,7 +66,26 @@
listViewArgs.activeSection
] = [$instanceRow.data('jsonObj')];
if (action.custom && !action.noAdd) {
var externalLinkAction = action.externalLink;
if (externalLinkAction) {
// Show popup immediately, do not proceed through normal action process
window.open(
// URL
externalLinkAction.url({
context: context
}),
// Title
externalLinkAction.title({
context: context
}),
// Window options
'menubar=0,resizable=0,'
+ 'width=' + externalLinkAction.width + ','
+ 'height=' + externalLinkAction.height
);
} else if (action.custom && !action.noAdd) {
action.custom({
data: data,
ref: options.ref,
@ -254,7 +273,8 @@
listViewArgs.activeSection
] = [$instanceRow.data('jsonObj')];
if (!args.action.createForm &&
if (!args.action.action.externalLink &&
!args.action.createForm &&
args.action.addRow != 'true' &&
!action.custom && !action.uiCustom)
cloudStack.dialog.confirm({
@ -274,7 +294,26 @@
var isHeader = args.action.isHeader;
var createFormContext = $.extend({}, context);
if (args.action.createForm) {
var externalLinkAction = action.externalLink;
if (externalLinkAction) {
// Show popup immediately, do not proceed through normal action process
window.open(
// URL
externalLinkAction.url({
context: context
}),
// Title
externalLinkAction.title({
context: context
}),
// Window options
'menubar=0,resizable=0,'
+ 'width=' + externalLinkAction.width + ','
+ 'height=' + externalLinkAction.height
);
} else if (args.action.createForm) {
cloudStack.dialog.createForm({
form: args.action.createForm,
after: function(args) {

View File

@ -71,15 +71,48 @@ import com.cloud.utils.mgmt.JmxUtil;
import com.cloud.utils.mgmt.ManagementBean;
/**
* ComponentLocator manages all of the adapters within a system. It operates on
* top of an components.xml and uses reflection to instantiate all of the
* adapters. It also supports rereading of all of the adapters.
* ComponentLocator ties together several different concepts. First, it
* deals with how a system should be put together. It manages different
* types of components:
* - Manager: Singleton implementation of a certain process.
* - Adapter: Different singleton implementations for the same functions.
* - SystemIntegrityChecker: Singletons that are called at the load time.
* - Dao: Data Access Objects.
*
* These components can be declared in several ways:
* - ComponentLibrary - A Java class that declares the above components. The
* advantage of declaring components here is they change automatically
* with any refactoring.
* - components specification - An xml file that overrides the
* ComponentLibrary. The advantage of declaring components here is
* they can change by hand on every deployment.
*
* The two are NOT mutually exclusive. ComponentLocator basically locates
* the components specification, which specifies the ComponentLibrary within.
* Components found in the ComponentLibrary are overridden by components
* found in components specification.
*
* Components specification can also be nested. One components specification
* can point to another components specification and, therefore, "inherits"
* those components but still override one or more components. ComponentLocator
* reads the child components specification first and follow the chain up.
* the child's components overrides the ones in the parent.
*
* ComponentLocator looks for the components specification as follows:
* 1. By following the path specified by "cloud-stack-components-specification"
* within the environment.properties file.
* 2. Look for components.xml in the class path.
*
* ComponentLocator also ties in component injection. Components can specify
* an @Inject annotation to components ComponentLocator knows. When
* instantiating components, ComponentLocator attempts to inject these
* components.
*
**/
@SuppressWarnings("unchecked")
public class ComponentLocator implements ComponentLocatorMBean {
protected static final Logger s_logger = Logger.getLogger(ComponentLocator.class);
protected static final ThreadLocal<ComponentLocator> s_tl = new ThreadLocal<ComponentLocator>();
protected static final ConcurrentHashMap<Class<?>, Singleton> s_singletons = new ConcurrentHashMap<Class<?>, Singleton>(111);
protected static final HashMap<String, ComponentLocator> s_locators = new HashMap<String, ComponentLocator>();
@ -90,7 +123,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
protected static CallbackFilter s_callbackFilter = new DatabaseCallbackFilter();
protected static final List<AnnotationInterceptor<?>> s_interceptors = new ArrayList<AnnotationInterceptor<?>>();
protected static CleanupThread s_janitor = null;
protected HashMap<String, Adapters<? extends Adapter>> _adapterMap;
protected HashMap<String, ComponentInfo<Manager>> _managerMap;
protected LinkedHashMap<String, ComponentInfo<SystemIntegrityChecker>> _checkerMap;
@ -98,8 +131,8 @@ public class ComponentLocator implements ComponentLocatorMBean {
protected String _serverName;
protected Object _component;
protected HashMap<Class<?>, Class<?>> _factories;
protected HashMap<String, ComponentInfo<PluggableService>> _pluggableServicesMap;
protected HashMap<String, ComponentInfo<PluggableService>> _pluginsMap;
static {
if (s_janitor == null) {
s_janitor = new CleanupThread();
@ -118,7 +151,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
public String getLocatorName() {
return _serverName;
}
@Override
public String getName() {
return getLocatorName();
@ -133,7 +166,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
_checkerMap = new LinkedHashMap<String, ComponentInfo<SystemIntegrityChecker>>();
_adapterMap = new HashMap<String, Adapters<? extends Adapter>>();
_factories = new HashMap<Class<?>, Class<?>>();
_pluggableServicesMap = new LinkedHashMap<String, ComponentInfo<PluggableService>>();
_pluginsMap = new LinkedHashMap<String, ComponentInfo<PluggableService>>();
File file = PropertiesUtil.findConfigFile(filename);
if (file == null) {
s_logger.info("Unable to find " + filename);
@ -157,7 +190,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
_daoMap.putAll(parentLocator._daoMap);
_managerMap.putAll(parentLocator._managerMap);
_factories.putAll(parentLocator._factories);
_pluggableServicesMap.putAll(parentLocator._pluggableServicesMap);
_pluginsMap.putAll(parentLocator._pluginsMap);
}
ComponentLibrary library = null;
@ -168,15 +201,15 @@ public class ComponentLocator implements ComponentLocatorMBean {
_managerMap.putAll(library.getManagers());
adapters.putAll(library.getAdapters());
_factories.putAll(library.getFactories());
_pluggableServicesMap.putAll(library.getPluggableServices());
_pluginsMap.putAll(library.getPluggableServices());
}
_daoMap.putAll(handler.daos);
_managerMap.putAll(handler.managers);
_checkerMap.putAll(handler.checkers);
adapters.putAll(handler.adapters);
_pluggableServicesMap.putAll(handler.pluggableServices);
_pluginsMap.putAll(handler.pluggableServices);
return new Pair<XmlHandler, HashMap<String, List<ComponentInfo<Adapter>>>>(handler, adapters);
} catch (ParserConfigurationException e) {
s_logger.error("Unable to load " + _serverName + " due to errors while parsing " + filename, e);
@ -203,7 +236,9 @@ public class ComponentLocator implements ComponentLocatorMBean {
s_logger.info("Skipping configuration using " + filename);
return;
}
instantiatePluggableServices();
XmlHandler handler = result.first();
HashMap<String, List<ComponentInfo<Adapter>>> adapters = result.second();
try {
@ -220,13 +255,12 @@ public class ComponentLocator implements ComponentLocatorMBean {
startAdapters();
//TODO do we need to follow the instantiate -> inject -> configure -> start -> stop flow of singletons like managers/adapters?
//TODO do we need to expose pluggableServices to MBean (provide getNames?)
instantiatePluggableServices();
} catch (CloudRuntimeException e) {
s_logger.error("Unable to load configuration for " + _serverName + " from " + filename, e);
System.exit(1);
} catch (Exception e) {
s_logger.error("Unable to load configuration for " + _serverName + " from " + filename, e);
System.exit(1);
s_logger.error("Unable to load configuration for " + _serverName + " from " + filename, e);
System.exit(1);
}
}
@ -288,7 +322,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
}
}
private static Object createInstance(Class<?> clazz, boolean inject, boolean singleton, Object... args) {
Factory factory = null;
Singleton entity = null;
@ -313,8 +347,8 @@ public class ComponentLocator implements ComponentLocatorMBean {
factory = info.factory;
}
}
Class<?>[] argTypes = null;
if (args != null && args.length > 0) {
Constructor<?>[] constructors = clazz.getConstructors();
@ -334,49 +368,49 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
}
}
if (argTypes == null) {
throw new CloudRuntimeException("Unable to find constructor to match parameters given: " + clazz.getName());
}
entity = new Singleton(factory.newInstance(argTypes, args, s_callbacks));
} else {
entity = new Singleton(factory.newInstance(s_callbacks));
}
if (inject) {
inject(clazz, entity.singleton);
entity.state = Singleton.State.Injected;
}
if (singleton) {
synchronized(s_factories) {
s_singletons.put(clazz, entity);
}
}
return entity.singleton;
}
protected ComponentInfo<GenericDao<?, ?>> getDao(String name) {
ComponentInfo<GenericDao<?, ?>> info = _daoMap.get(name);
if (info == null) {
throw new CloudRuntimeException("Unable to find DAO " + name);
}
return info;
}
public static synchronized Object getComponent(String componentName) {
synchronized(_hasCheckerRun) {
/* System Integrity checker will run before all components really loaded */
if (!_hasCheckerRun && !componentName.equalsIgnoreCase(SystemIntegrityChecker.Name)) {
ComponentLocator.getComponent(SystemIntegrityChecker.Name);
_hasCheckerRun = true;
}
}
synchronized(_hasCheckerRun) {
/* System Integrity checker will run before all components really loaded */
if (!_hasCheckerRun && !componentName.equalsIgnoreCase(SystemIntegrityChecker.Name)) {
ComponentLocator.getComponent(SystemIntegrityChecker.Name);
_hasCheckerRun = true;
}
}
ComponentLocator locator = s_locators.get(componentName);
if (locator == null) {
locator = ComponentLocator.getLocator(componentName);
@ -441,10 +475,10 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
}
}
protected static void inject(Class<?> clazz, Object entity) {
ComponentLocator locator = ComponentLocator.getCurrentLocator();
do {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
@ -467,11 +501,11 @@ public class ComponentLocator implements ComponentLocatorMBean {
s_logger.trace("Other:" + fc.getName());
instance = locator.getManager(fc);
}
if (instance == null) {
throw new CloudRuntimeException("Unable to inject " + fc.getSimpleName() + " in " + clazz.getSimpleName());
}
try {
field.setAccessible(true);
field.set(entity, instance);
@ -545,7 +579,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
return (T)info.instance;
}
protected void configureAdapters() {
for (Adapters<? extends Adapter> adapters : _adapterMap.values()) {
List<ComponentInfo<Adapter>> infos = adapters._infos;
@ -597,7 +631,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
_adapterMap.put(entry.getKey(), adapters);
}
}
protected void instantiateAdapters(Map<String, List<ComponentInfo<Adapter>>> map) {
Set<Map.Entry<String, List<ComponentInfo<Adapter>>>> entries = map.entrySet();
for (Map.Entry<String, List<ComponentInfo<Adapter>>> entry : entries) {
@ -641,18 +675,26 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
protected void instantiatePluggableServices() {
Set<Map.Entry<String, ComponentInfo<PluggableService>>> entries = _pluggableServicesMap.entrySet();
Set<Map.Entry<String, ComponentInfo<PluggableService>>> entries = _pluginsMap.entrySet();
for (Map.Entry<String, ComponentInfo<PluggableService>> entry : entries) {
ComponentInfo<PluggableService> info = entry.getValue();
if (info.instance == null) {
s_logger.info("Instantiating PluggableService: " + info.name);
info.instance = (PluggableService)createInstance(info.clazz, false, info.singleton);
if (info.instance instanceof Plugin) {
Plugin plugin = (Plugin)info.instance;
ComponentLibrary lib = plugin.getComponentLibrary();
_managerMap.putAll(lib.getManagers());
_daoMap.putAll(lib.getDaos());
}
}
}
}
protected ComponentInfo<PluggableService> getPluggableService(String name) {
ComponentInfo<PluggableService> mgr = _pluggableServicesMap.get(name);
ComponentInfo<PluggableService> mgr = _pluginsMap.get(name);
return mgr;
}
@ -669,7 +711,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
public <T> List<T> getAllPluggableServices() {
List<T> services = new ArrayList<T>();
Set<Map.Entry<String, ComponentInfo<PluggableService>>> entries = _pluggableServicesMap.entrySet();
Set<Map.Entry<String, ComponentInfo<PluggableService>>> entries = _pluginsMap.entrySet();
for (Map.Entry<String, ComponentInfo<PluggableService>> entry : entries) {
ComponentInfo<PluggableService> info = entry.getValue();
if (info.instance == null) {
@ -680,11 +722,11 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
return services;
}
public static <T> T inject(Class<T> clazz) {
return (T)createInstance(clazz, true, false);
}
public <T> T createInstance(Class<T> clazz) {
Class<? extends T> impl = (Class<? extends T>)_factories.get(clazz);
if (impl == null) {
@ -692,11 +734,11 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
return inject(impl);
}
public static <T> T inject(Class<T> clazz, Object... args) {
return (T)createInstance(clazz, true, false, args);
}
@Override
public Map<String, List<String>> getAdapterNames() {
HashMap<String, List<String>> result = new HashMap<String, List<String>>();
@ -749,7 +791,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
return new Adapters<Adapter>(key, new ArrayList<ComponentInfo<Adapter>>());
}
protected void resetInterceptors(InterceptorLibrary library) {
library.addInterceptors(s_interceptors);
if (s_interceptors.size() > 0) {
@ -781,7 +823,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
s_once = true;
}
}
ComponentLocator locator;
synchronized (s_locators) {
locator = s_locators.get(server);
@ -822,7 +864,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
} catch (IOException e) {
s_logger.debug("environment.properties could not be loaded:" + e.toString());
}
if (configFile == null || PropertiesUtil.findConfigFile(configFile) == null) {
configFile = "components.xml";
if (PropertiesUtil.findConfigFile(configFile) == null){
@ -843,31 +885,31 @@ public class ComponentLocator implements ComponentLocatorMBean {
List<String> keys = new ArrayList<String>();
T instance;
boolean singleton = true;
protected ComponentInfo() {
}
public List<String> getKeys() {
return keys;
}
public String getName() {
return name;
}
public ComponentInfo(String name, Class<? extends T> clazz) {
this(name, clazz, new ArrayList<Pair<String, Object>>(0));
}
public ComponentInfo(String name, Class<? extends T> clazz, T instance) {
this(name, clazz);
this.instance = instance;
}
public ComponentInfo(String name, Class<? extends T> clazz, List<Pair<String, Object>> params) {
this(name, clazz, params, true);
}
public ComponentInfo(String name, Class<? extends T> clazz, List<Pair<String, Object>> params, boolean singleton) {
this.name = name;
this.clazz = clazz;
@ -877,10 +919,10 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
fillInfo();
}
protected void fillInfo() {
String clazzName = clazz.getName();
Local local = clazz.getAnnotation(Local.class);
if (local == null) {
throw new CloudRuntimeException("Unable to find Local annotation for class " + clazzName);
@ -900,7 +942,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
}
}
public void addParameter(String name, String value) {
params.put(name, value);
}
@ -964,13 +1006,13 @@ public class ComponentLocator implements ComponentLocatorMBean {
if (singleton != null) {
info.singleton = Boolean.parseBoolean(singleton);
}
info.fillInfo();
}
@Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
throws SAXException {
throws SAXException {
if (qName.equals("interceptor") && s_interceptors.size() == 0) {
synchronized(s_interceptors){
if (s_interceptors.size() == 0) {
@ -1001,7 +1043,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
throw new CloudRuntimeException("Unable to find " + implementationClass, e);
}
}
library = getAttribute(atts, "library");
}
} else if (qName.equals("adapters")) {
@ -1041,7 +1083,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
checkers.put(info.name, info);
s_logger.info("Adding system integrity checker: " + info.name);
currentInfo = info;
} else if (qName.equals("pluggableservice")) {
} else if (qName.equals("pluggableservice") || qName.equals("plugin")) {
ComponentInfo<PluggableService> info = new ComponentInfo<PluggableService>();
fillInfo(atts, PluggableService.class, info);
s_logger.info("Adding PluggableService: " + info.name);
@ -1096,17 +1138,17 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
}
}
protected static class InjectInfo {
public Factory factory;
public Enhancer enhancer;
public InjectInfo(Enhancer enhancer, Factory factory) {
this.factory = factory;
this.enhancer = enhancer;
}
}
protected static class CleanupThread extends Thread {
@Override
public void run() {
@ -1133,7 +1175,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
}
}
for (ComponentLocator locator : s_locators.values()) {
Iterator<ComponentInfo<Manager>> itManagers = locator._managerMap.values().iterator();
while (itManagers.hasNext()) {
@ -1154,7 +1196,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
}
}
static class Singleton {
public enum State {
Instantiated,
@ -1163,16 +1205,16 @@ public class ComponentLocator implements ComponentLocatorMBean {
Started,
Stopped
}
public Object singleton;
public State state;
public Singleton(Object singleton) {
this.singleton = singleton;
this.state = State.Instantiated;
}
}
protected class InterceptorDispatcher implements MethodInterceptor {
@Override
@ -1200,7 +1242,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
}
}
protected static class InterceptorFilter implements CallbackFilter {
@Override
public int accept(Method method) {
@ -1215,7 +1257,7 @@ public class ComponentLocator implements ComponentLocatorMBean {
}
}
}
return index;
}
}

View File

@ -17,6 +17,7 @@
package com.cloud.utils.component;
/**
* This interface defines methods for pluggable code within the Cloud Stack.
*/
@ -26,5 +27,5 @@ public interface PluggableService {
* The config file name that lists API commands supported by this pluggable service
*/
String getPropertiesFile();
}

View File

@ -0,0 +1,64 @@
// 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
// 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.utils.component;
import java.util.List;
import com.cloud.utils.Pair;
/**
* CloudStack uses Adapters to implement different capabilities.
* There are different Adapters such as NetworkGuru, NetworkElement,
* HypervisorGuru, DeploymentPlanner, etc. However, Adapters only
* defines what CloudStack needs from the implementation. What about
* what the Adapter itself needs, such as configurations and administrative
* operations, and what if one implementation can
* implement two different Adapters?
*
* Plugin is a CloudStack container for Adapters. It rolls the following
* capabilities into the one package for CloudStack to load at runtime.
* - REST API commands supported by the Plugin.
* - Components needed by the Plugin.
* - Adapters implemented by the Plugin.
* - Database operations
*
*/
public interface Plugin extends PluggableService {
/**
* Retrieves the component libraries needed by this Plugin.
* ComponentLocator put these components and add them to the startup
* and shutdown processes of CloudStack. This is only needed if the
* Plugin uses ComponentLocator to inject what it needs. If the
* Plugin uses other mechanisms, then it can return null here.
*
* @return a component library that contains the components this Plugin
* contains and needs.
*/
ComponentLibrary getComponentLibrary();
/**
* Retrieves the list of Adapters and the interface they implement. It
* can be an empty list if the Plugin does not implement any.
*
* @return list of pairs where the first is the interface and the second
* is the adapter.
*/
List<Pair<Class<?>, Class<? extends Adapter>>> getAdapterImplementations();
}

File diff suppressed because it is too large Load Diff