diff --git a/core/src/com/cloud/user/dao/AccountDaoImpl.java b/core/src/com/cloud/user/dao/AccountDaoImpl.java index 1b60f22d2b4..5715ac58515 100644 --- a/core/src/com/cloud/user/dao/AccountDaoImpl.java +++ b/core/src/com/cloud/user/dao/AccountDaoImpl.java @@ -174,7 +174,7 @@ public class AccountDaoImpl extends GenericDaoBase implements A @Override public void markForCleanup(long accountId) { - AccountVO account = findById(accountId); + AccountVO account = findByIdIncludingRemoved(accountId); if (!account.getNeedsCleanup()) { account.setNeedsCleanup(true); update(accountId, account); diff --git a/server/src/com/cloud/api/response/ExceptionResponse.java b/server/src/com/cloud/api/response/ExceptionResponse.java new file mode 100644 index 00000000000..49542de481e --- /dev/null +++ b/server/src/com/cloud/api/response/ExceptionResponse.java @@ -0,0 +1,45 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class ExceptionResponse extends BaseResponse { + @SerializedName("errorcode") @Param(description="numeric code associated with this error") + private Integer errorCode; + + @SerializedName("errortext") @Param(description="the text associated with this error") + private String errorText; + + public Integer getErrorCode() { + return errorCode; + } + + public void setErrorCode(Integer errorCode) { + this.errorCode = errorCode; + } + + public String getErrorText() { + return errorText; + } + + public void setErrorText(String errorText) { + this.errorText = errorText; + } +} diff --git a/server/src/com/cloud/async/AsyncJobManagerImpl.java b/server/src/com/cloud/async/AsyncJobManagerImpl.java index 2a496fc37a1..ec49a4296d5 100644 --- a/server/src/com/cloud/async/AsyncJobManagerImpl.java +++ b/server/src/com/cloud/async/AsyncJobManagerImpl.java @@ -38,6 +38,7 @@ import com.cloud.api.ApiDispatcher; import com.cloud.api.BaseAsyncCmd; import com.cloud.api.BaseCmd; import com.cloud.api.ServerApiException; +import com.cloud.api.response.ExceptionResponse; import com.cloud.async.dao.AsyncJobDao; import com.cloud.cluster.ClusterManager; import com.cloud.configuration.dao.ConfigurationDao; @@ -323,6 +324,7 @@ public class AsyncJobManagerImpl implements AsyncJobManager { public void run() { long jobId = 0; + BaseAsyncCmd cmdObj = null; Transaction txn = Transaction.open(Transaction.CLOUD_DB); try { jobId = job.getId(); @@ -333,7 +335,7 @@ public class AsyncJobManagerImpl implements AsyncJobManager { } Class cmdClass = Class.forName(job.getCmd()); - BaseAsyncCmd cmdObj = (BaseAsyncCmd)cmdClass.newInstance(); + cmdObj = (BaseAsyncCmd)cmdClass.newInstance(); cmdObj.setAsyncJobManager(mgr); cmdObj.setJob(job); @@ -379,13 +381,25 @@ public class AsyncJobManagerImpl implements AsyncJobManager { } checkQueue(((AsyncCommandQueued)e).getQueue().getId()); } else { + String errorMsg = null; + int errorCode = BaseCmd.INTERNAL_ERROR; if (!(e instanceof ServerApiException)) { s_logger.error("Unexpected exception while executing " + job.getCmd(), e); + errorMsg = e.getMessage(); + } else { + ServerApiException sApiEx = (ServerApiException)e; + errorMsg = sApiEx.getDescription(); + errorCode = sApiEx.getErrorCode(); } + ExceptionResponse response = new ExceptionResponse(); + response.setErrorCode(errorCode); + response.setErrorText(errorMsg); + response.setResponseName((cmdObj == null) ? "unknowncommandresponse" : cmdObj.getName()); + // FIXME: setting resultCode to BaseCmd.INTERNAL_ERROR is not right, usually executors have their exception handling // and we need to preserve that as much as possible here - completeAsyncJob(jobId, AsyncJobResult.STATUS_FAILED, BaseCmd.INTERNAL_ERROR, e.getMessage()); + completeAsyncJob(jobId, AsyncJobResult.STATUS_FAILED, BaseCmd.INTERNAL_ERROR, response); // need to clean up any queue that happened as part of the dispatching and move on to the next item in the queue try { diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index a454904c77d..b346e2fa274 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -821,7 +821,7 @@ public class ManagementServerImpl implements ManagementServer { s_logger.debug("Remove account " + accountId); } - AccountVO account = _accountDao.findById(accountId); + AccountVO account = _accountDao.findByIdIncludingRemoved(accountId); deleteAccount(account); EventUtils.saveEvent(Long.valueOf(1), Long.valueOf(1), EventVO.LEVEL_INFO, EventTypes.EVENT_USER_DELETE, "User " + username + " (id: " + userId + ") for accountId = " + accountId + " and domainId = " + userAccount.getDomainId() + " was deleted."); diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index e589b3bd2ce..05b2f75e68e 100644 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -125,7 +125,7 @@ public class AccountManagerImpl implements AccountManager { // on a per-domain basis, decrement the count // FIXME: can this decrement be done on the database side in a custom update statement? - Account account = _accountDao.findById(accountId); + Account account = _accountDao.findByIdIncludingRemoved(accountId); // find all accounts, even removed accounts if this happens to be for an account that's being deleted Long domainId = account.getDomainId(); while (domainId != null) { _resourceCountDao.updateDomainCount(domainId, type, false, numToDecrement); diff --git a/ui/new/css/main.css b/ui/new/css/main.css index aaf2cbbddc2..8967697836f 100644 --- a/ui/new/css/main.css +++ b/ui/new/css/main.css @@ -2012,48 +2012,7 @@ a:hover.search_button { padding:0; } -.actionsdropdown_boxlist { - width:197px; - height:auto; - float:left; - margin:0 0 5px 6px; - padding:0 0 10px 0; - list-style:none; -} -.actionsdropdown_boxlist li{ - width:194px; - height:auto; - float:left; - text-align:left; - background:#FFF url(../images/midmenu_hover.gif) repeat-x top left; - color:#CCC; - font-size:11px; - font-weight:normal; - margin:0 0 0 0; - padding:6px 0 5px 3px; - list-style:none; -} - -.actionsdropdown_boxlist li:hover{ - background:#e6e6e6 repeat top left; -} - -.actionsdropdown_boxlist a{ - text-decoration:none; - color:#2c8bbc; -} - - -.actionsdropdown_boxlist a:link, actionsdropdown_boxlist a:visited { - text-decoration:none; - color:#2c8bbc; -} - -.actionsdropdown_boxlist a:hover{ - text-decoration:none; - color:#2c8bbc; -} #contentwrapper{ height:100%; @@ -2740,19 +2699,43 @@ a:hover.search_button { padding:0; } -#footer p{ +.footer_testprovisiongtool{ width:auto; height:auto; float:left; - text-align:left; - font-size:11px; - font-weight:normal; - color:#c2c2c2; margin:9px 0 0 10px; display:inline; padding:0; } +.footer_testprovisiongtool_icon { + width:11px; + height:13px; + float:left; + background:url(../images/test_provisioning.png) no-repeat top left; + margin:0; + padding:0; +} +.footer_testprovisiongtool a{ + width:auto; + height:auto; + float:left; + text-decoration:none; + font-weight:normal; + color:#CCC; + margin:2px 0 0 7px; + display:inline; + padding:0; +} + +.footer_testprovisiongtool a:link, .footer_testprovisiongtool a:visited { + text-decoration:none; +} + +.footer_testprovisiongtool a:hover { + text-decoration:underline; +} + #footer span{ font-weight:bold; color:#CCC; @@ -3138,19 +3121,62 @@ a:hover.search_button { } .grid_actionsdropdown_box { - width:209px; + width:195px; height:auto; float:left; position:absolute; background:#FFF repeat top left; border:1px solid #CCC; top:18px; - right:1px; + right:0; margin:0; padding:0; z-index:1002; } +.actionsdropdown_boxlist { + width:183px; + height:auto; + float:left; + margin:0 0 5px 6px; + padding:0 0 10px 0; + list-style:none; +} + +.actionsdropdown_boxlist li{ + width:181px; + height:auto; + float:left; + text-align:left; + background:#FFF url(../images/midmenu_hover.gif) repeat-x top left; + color:#CCC; + font-size:11px; + font-weight:normal; + margin:0 0 0 0; + padding:6px 0 5px 3px; + list-style:none; +} + +.actionsdropdown_boxlist li:hover{ + background:#e6e6e6 repeat top left; +} + +.actionsdropdown_boxlist a{ + text-decoration:none; + color:#2c8bbc; +} + + +.actionsdropdown_boxlist a:link, actionsdropdown_boxlist a:visited { + text-decoration:none; + color:#2c8bbc; +} + +.actionsdropdown_boxlist a:hover{ + text-decoration:none; + color:#2c8bbc; +} + .dbrow { width:100%; height:44px; diff --git a/ui/new/images/test_provisioning.png b/ui/new/images/test_provisioning.png index b962f16bc05..2e9f720942e 100644 Binary files a/ui/new/images/test_provisioning.png and b/ui/new/images/test_provisioning.png differ diff --git a/ui/new/index.jsp b/ui/new/index.jsp index daa35e9d8f2..d06bb93580b 100644 --- a/ui/new/index.jsp +++ b/ui/new/index.jsp @@ -677,9 +677,10 @@ long milliseconds = new Date().getTime(); diff --git a/utils/src/com/cloud/utils/db/GenericDaoBase.java b/utils/src/com/cloud/utils/db/GenericDaoBase.java index 53df12503e4..236d49980bb 100755 --- a/utils/src/com/cloud/utils/db/GenericDaoBase.java +++ b/utils/src/com/cloud/utils/db/GenericDaoBase.java @@ -1137,7 +1137,7 @@ public abstract class GenericDaoBase implements Gene } } - return _idField != null ? findById(id) : null; + return _idField != null ? findByIdIncludingRemoved(id) : null; } @DB(txn=false)