diff --git a/core/src/com/cloud/agent/AgentManager.java b/core/src/com/cloud/agent/AgentManager.java index fac5b8be354..4893f78d920 100755 --- a/core/src/com/cloud/agent/AgentManager.java +++ b/core/src/com/cloud/agent/AgentManager.java @@ -210,4 +210,6 @@ public interface AgentManager extends Manager { public boolean reconnect(final long hostId) throws AgentUnavailableException; public List discoverHosts(long dcId, Long podId, Long clusterId, URI url, String username, String password) throws DiscoveryException; + + Answer easySend(Long hostId, Command cmd, int timeout); } diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index d79bfffc56c..2834711152b 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -3480,8 +3480,12 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR return false; return true; } - protected String callHostPlugin(String plugin, String cmd, String... params) { + //default time out is 300 s + return callHostPluginWithTimeOut(plugin, cmd, 300, params); + } + + protected String callHostPluginWithTimeOut(String plugin, String cmd, int timeout, String... params) { Map args = new HashMap(); Session slaveSession = null; Connection slaveConn = null; @@ -3493,7 +3497,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR // TODO Auto-generated catch block e.printStackTrace(); } - slaveConn = new Connection(slaveUrl, 1800); + slaveConn = new Connection(slaveUrl, timeout); slaveSession = Session.slaveLocalLoginWithPassword(slaveConn, _username, _password); if (s_logger.isDebugEnabled()) { @@ -6205,7 +6209,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR checksum = ""; } - String result = callHostPlugin("vmopsSnapshot", "post_create_private_template", "remoteTemplateMountPath", remoteTemplateMountPath, "templateDownloadFolder", templateDownloadFolder, + String result = callHostPluginWithTimeOut("vmopsSnapshot", "post_create_private_template", 110*60, "remoteTemplateMountPath", remoteTemplateMountPath, "templateDownloadFolder", templateDownloadFolder, "templateInstallFolder", templateInstallFolder, "templateFilename", templateFilename, "templateName", templateName, "templateDescription", templateDescription, "checksum", checksum, "virtualSize", String.valueOf(virtualSize), "templateId", String.valueOf(templateId)); @@ -6243,7 +6247,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR // Each argument is put in a separate line for readability. // Using more lines does not harm the environment. - String results = callHostPlugin("vmopsSnapshot", "backupSnapshot", "primaryStorageSRUuid", primaryStorageSRUuid, "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId", + String results = callHostPluginWithTimeOut("vmopsSnapshot", "backupSnapshot", 110*60, "primaryStorageSRUuid", primaryStorageSRUuid, "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId", volumeId.toString(), "secondaryStorageMountPath", secondaryStorageMountPath, "snapshotUuid", snapshotUuid, "prevSnapshotUuid", prevSnapshotUuid, "prevBackupUuid", prevBackupUuid, "isFirstSnapshotOfRootVolume", isFirstSnapshotOfRootVolume.toString(), "isISCSI", isISCSI.toString()); @@ -6346,7 +6350,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR String failureString = "Could not create volume from " + backedUpSnapshotUuid; templatePath = (templatePath == null) ? "" : templatePath; - String results = callHostPlugin("vmopsSnapshot", "createVolumeFromSnapshot", "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId", volumeId.toString(), + String results = callHostPluginWithTimeOut("vmopsSnapshot","createVolumeFromSnapshot", 110*60, "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId", volumeId.toString(), "secondaryStorageMountPath", secondaryStorageMountPath, "backedUpSnapshotUuid", backedUpSnapshotUuid, "templatePath", templatePath, "templateDownloadFolder", templateDownloadFolder, "isISCSI", isISCSI.toString()); diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 3de6fdf5809..d23290ddd7d 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -1132,11 +1132,16 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory { } } } + + @Override + public Answer easySend(final Long hostId, final Command cmd) { + return easySend(hostId, cmd, _wait); + } @Override - public Answer easySend(final Long hostId, final Command cmd) { + public Answer easySend(final Long hostId, final Command cmd, int timeout) { try { - final Answer answer = send(hostId, cmd, _wait); + final Answer answer = send(hostId, cmd, timeout); if (answer == null) { s_logger.warn("send returns null answer"); return null; diff --git a/server/src/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java index cab971738e1..ba612b71fc2 100755 --- a/server/src/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java +++ b/server/src/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java @@ -37,7 +37,6 @@ import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.dao.HostPodDao; import com.cloud.offering.NetworkOffering; -import com.cloud.offering.NetworkOffering.GuestIpType; import com.cloud.offering.ServiceOffering; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; @@ -50,7 +49,6 @@ import com.cloud.utils.DateUtil; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.Inject; -import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.SearchCriteria; import com.cloud.vm.State; import com.cloud.vm.UserVmVO; @@ -76,7 +74,6 @@ public class UserConcentratedAllocator implements PodAllocator { @Inject VMInstanceDao _vmInstanceDao; Random _rand = new Random(System.currentTimeMillis()); - private final GlobalLock m_capacityCheckLock = GlobalLock.getInternLock("capacity.check"); private int _hoursToSkipStoppedVMs = 24; private int _secStorageVmRamSize = 1024; @@ -156,30 +153,14 @@ public class UserConcentratedAllocator implements PodAllocator { private boolean dataCenterAndPodHasEnoughCapacity(long dataCenterId, long podId, long capacityNeeded, short capacityType, long[] hostCandidate) { List capacities = null; - if (m_capacityCheckLock.lock(120)) { // 2 minutes - try { - SearchCriteria sc = _capacityDao.createSearchCriteria(); - sc.addAnd("capacityType", SearchCriteria.Op.EQ, capacityType); - sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, dataCenterId); - sc.addAnd("podId", SearchCriteria.Op.EQ, podId); - capacities = _capacityDao.search(sc, null); - } finally { - m_capacityCheckLock.unlock(); - } - } else { - s_logger.error("Unable to acquire synchronization lock for pod allocation"); - - // we now try to enforce reservation-style allocation, waiting time has been adjusted - // to 2 minutes - return false; - -/* - // If we can't lock the table, just return that there is enough capacity and allow instance creation to fail on the agent - // if there is not enough capacity. All that does is skip the optimization of checking for capacity before sending the - // command to the agent. - return true; -*/ - } + + SearchCriteria sc = _capacityDao.createSearchCriteria(); + sc.addAnd("capacityType", SearchCriteria.Op.EQ, capacityType); + sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, dataCenterId); + sc.addAnd("podId", SearchCriteria.Op.EQ, podId); + s_logger.trace("Executing search"); + capacities = _capacityDao.search(sc, null); + s_logger.trace("Done with a search"); boolean enoughCapacity = false; if (capacities != null) { diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java index 033b1ba3282..9250bb86557 100644 --- a/server/src/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/com/cloud/alert/AlertManagerImpl.java @@ -65,8 +65,9 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentLocator; -import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.DB; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.SecondaryStorageVmVO; @@ -118,8 +119,6 @@ public class AlertManagerImpl implements AlertManager { private double _publicIPCapacityThreshold = 0.75; private double _privateIPCapacityThreshold = 0.75; - private final GlobalLock m_capacityCheckLock = GlobalLock.getInternLock("capacity.check"); - @Override public boolean configure(String name, Map params) throws ConfigurationException { _name = name; @@ -319,7 +318,7 @@ public class AlertManagerImpl implements AlertManager { } } - @Override + @Override @DB public void recalculateCapacity() { // FIXME: the right way to do this is to register a listener (see RouterStatsListener, VMSyncListener) // for the vm sync state. The listener model has connects/disconnects to keep things in sync much better @@ -435,25 +434,23 @@ public class AlertManagerImpl implements AlertManager { newCapacities.add(newPrivateIPCapacity); } - if (m_capacityCheckLock.lock(5)) { // 5 second timeout - try { - // delete the old records - _capacityDao.clearNonStorageCapacities(); + Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + // delete the old records + _capacityDao.clearNonStorageCapacities(); - for (CapacityVO newCapacity : newCapacities) { - _capacityDao.persist(newCapacity); - } - } finally { - m_capacityCheckLock.unlock(); - } - - if (s_logger.isTraceEnabled()) { - s_logger.trace("done recalculating system capacity"); - } - } else { - if (s_logger.isTraceEnabled()) { - s_logger.trace("Skipping capacity check, unable to lock the capacity table for recalculation."); - } + for (CapacityVO newCapacity : newCapacities) { + s_logger.trace("Executing capacity update"); + _capacityDao.persist(newCapacity); + s_logger.trace("Done with capacity update"); + } + txn.commit(); + } catch (Exception ex) { + txn.rollback(); + s_logger.error("Unable to start transaction for capacity update"); + }finally { + txn.close(); } } diff --git a/server/src/com/cloud/api/commands/ListVMsCmd.java b/server/src/com/cloud/api/commands/ListVMsCmd.java index add2a51445d..68ffa17b314 100644 --- a/server/src/com/cloud/api/commands/ListVMsCmd.java +++ b/server/src/com/cloud/api/commands/ListVMsCmd.java @@ -182,6 +182,14 @@ public class ListVMsCmd extends BaseCmd { } for (UserVm vmInstance : virtualMachines) { + + //if the account is deleted, do not return the user vm + Account currentVmAccount = getManagementServer().getAccount(vmInstance.getAccountId()); + if(currentVmAccount.getRemoved()!=null) + { + continue; //not returning this vm + } + List> vmData = new ArrayList>(); AsyncJobVO asyncJob = getManagementServer().findInstancePendingAsyncJob("vm_instance", vmInstance.getId()); if(asyncJob != null) { diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 58cfe27cdf8..668d4674171 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -61,6 +61,7 @@ import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; import com.cloud.vm.VmStats; @@ -99,7 +100,7 @@ public class StatsCollector { long storageStatsInterval = -1L; long volumeStatsInterval = -1L; - private final GlobalLock m_capacityCheckLock = GlobalLock.getInternLock("capacity.check"); + //private final GlobalLock m_capacityCheckLock = GlobalLock.getInternLock("capacity.check"); public static StatsCollector getInstance() { return s_instance; @@ -335,32 +336,25 @@ public class StatsCollector { // _capacityDao.persist(capacity); } - if (m_capacityCheckLock.lock(5)) { // 5 second timeout - if (s_logger.isTraceEnabled()) { - s_logger.trace("recalculating system storage capacity"); - } - try { - // now update the capacity table with the new stats - // FIXME: the right way to do this is to register a listener (see RouterStatsListener) - // for the host stats, send the WatchCommand at a regular interval - // to collect the stats from an agent and update the database as needed. The - // listener model has connects/disconnects to keep things in sync much better - // than this model right now - _capacityDao.clearStorageCapacities(); + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + if (s_logger.isTraceEnabled()) { + s_logger.trace("recalculating system storage capacity"); + } + txn.start(); + _capacityDao.clearStorageCapacities(); - for (CapacityVO newCapacity : newCapacities) { - _capacityDao.persist(newCapacity); - } - } finally { - m_capacityCheckLock.unlock(); - } - if (s_logger.isTraceEnabled()) { - s_logger.trace("done recalculating system storage capacity"); - } - } else { - if (s_logger.isTraceEnabled()) { - s_logger.trace("not recalculating system storage capacity, unable to lock capacity table"); - } + for (CapacityVO newCapacity : newCapacities) { + s_logger.trace("Executing capacity update"); + _capacityDao.persist(newCapacity); + s_logger.trace("Done with capacity update"); + } + txn.commit(); + } catch (Exception ex) { + txn.rollback(); + s_logger.error("Unable to start transaction for storage capacity update"); + }finally { + txn.close(); } } catch (Throwable t) { s_logger.error("Error trying to retrieve storage stats", t); diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index f6d9aa72de0..1e8e3255050 100644 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -19,11 +19,7 @@ package com.cloud.storage; import java.net.URI; import java.net.UnknownHostException; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.Enumeration; @@ -33,7 +29,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -94,9 +89,9 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceInUseException; import com.cloud.exception.StorageUnavailableException; import com.cloud.host.Host; -import com.cloud.host.Host.Type; import com.cloud.host.HostVO; import com.cloud.host.Status; +import com.cloud.host.Host.Type; import com.cloud.host.dao.DetailsDao; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; @@ -127,12 +122,9 @@ import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountVO; import com.cloud.user.User; -import com.cloud.user.UserContext; -import com.cloud.user.UserVO; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; -import com.cloud.utils.DateUtil; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.Adapters; @@ -1805,7 +1797,8 @@ public class StorageManagerImpl implements StorageManager { } } s_logger.debug("Trying to execute Command: " + cmd + " on host: " + hostId + " try: " + tryCount); - answer = _agentMgr.send(hostId, cmd); + // set 120 min timeout for storage related command + answer = _agentMgr.send(hostId, cmd, 120*60*1000); if (answer != null && answer.getResult()) { return answer; @@ -1963,8 +1956,6 @@ public class StorageManagerImpl implements StorageManager { { boolean destroyVolumes = false; long count = 1; - long consoleProxyId = 0; - long ssvmId = 0; try { //1. Get the primary storage record @@ -2023,9 +2014,20 @@ public class StorageManagerImpl implements StorageManager { { if(destroyVolumes) { - //proxy vm is stopped, and we have another ps available - //get the id for restart - consoleProxyId = vmInstance.getId(); + //create a dummy event + long eventId1 = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_PROXY_START, "starting console proxy with Id: "+vmInstance.getId()); + + //Restore config val for consoleproxy.restart to true + _configMgr.updateConfiguration(userId, "consoleproxy.restart", "true"); + + if(_consoleProxyMgr.startProxy(vmInstance.getId(), eventId1)==null) + { + s_logger.warn("There was an error starting the console proxy id: "+vmInstance.getId()+" on another storage pool, cannot enable primary storage maintenance"); + primaryStorage.setStatus(Status.ErrorInMaintenance); + _storagePoolDao.persist(primaryStorage); + return false; + } + } } } @@ -2064,9 +2066,15 @@ public class StorageManagerImpl implements StorageManager { { if(destroyVolumes) { - //ss vm is stopped, and we have another ps available - //get the id for restart - ssvmId = vmInstance.getId(); + //create a dummy event and restart the ssvm immediately + long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_SSVM_START, "starting ssvm with Id: "+vmInstance.getId()); + if(_secStorageMgr.startSecStorageVm(vmInstance.getId(), eventId)==null) + { + s_logger.warn("There was an error starting the ssvm id: "+vmInstance.getId()+" on another storage pool, cannot enable primary storage maintenance"); + primaryStorage.setStatus(Status.ErrorInMaintenance); + _storagePoolDao.persist(primaryStorage); + return false; + } } } @@ -2100,34 +2108,7 @@ public class StorageManagerImpl implements StorageManager { _volsDao.remove(vol.getId()); } - //5. Restart all the system vms conditionally - if(destroyVolumes) //this means we have another ps. Ok to restart - { - //create a dummy event - long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_SSVM_START, "starting ssvm with Id: "+ssvmId); - if(_secStorageMgr.startSecStorageVm(ssvmId, eventId)==null) - { - s_logger.warn("There was an error starting the ssvm id: "+ssvmId+" on another storage pool, cannot enable primary storage maintenance"); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); - return false; - } - - //create a dummy event - long eventId1 = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_PROXY_START, "starting console proxy with Id: "+consoleProxyId); - - //Restore config val for consoleproxy.restart to true - _configMgr.updateConfiguration(userId, "consoleproxy.restart", "true"); - - if(_consoleProxyMgr.startProxy(consoleProxyId, eventId1)==null) - { - s_logger.warn("There was an error starting the console proxy id: "+consoleProxyId+" on another storage pool, cannot enable primary storage maintenance"); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); - return false; } - } - - //6. Update the status + //5. Update the status primaryStorage.setStatus(Status.Maintenance); _storagePoolDao.persist(primaryStorage); diff --git a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java index e0ae7a9e756..d29e51d11cf 100644 --- a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java @@ -142,7 +142,12 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement return false; } - + //if pool is NOT in up state, return false + if(!pool.getStatus().equals(com.cloud.host.Status.Up))//this is the pool status + { + return false; + } + // Check that the pool type is correct if (!poolIsCorrectType(dskCh, pool, vm, offering)) { return false; diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 71fe9be0052..04f4a110847 100644 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -236,7 +236,8 @@ public class TemplateManagerImpl implements TemplateManager { s_logger.debug("Downloading " + templateId + " via " + vo.getHostId()); } dcmd.setLocalPath(vo.getLocalPath()); - DownloadAnswer answer = (DownloadAnswer)_agentMgr.easySend(vo.getHostId(), dcmd); + // set 120 min timeout for this command + DownloadAnswer answer = (DownloadAnswer)_agentMgr.easySend(vo.getHostId(), dcmd, 120*60*1000); if (answer != null) { templateStoragePoolRef.setDownloadPercent(templateStoragePoolRef.getDownloadPercent()); templateStoragePoolRef.setDownloadState(answer.getDownloadStatus()); diff --git a/setup/bindir/cloud-setup-databases.in b/setup/bindir/cloud-setup-databases.in index e12a4c99d48..9543cb19571 100755 --- a/setup/bindir/cloud-setup-databases.in +++ b/setup/bindir/cloud-setup-databases.in @@ -171,7 +171,8 @@ def ifaces(): def ip(iface): status,lines = commands.getstatusoutput('LANG=C /sbin/ip address show %s'%iface) - assert status == 0 + if status != 0: return False + #used to say: assert status == 0 but it caused a bug in ifaces without IP lines = [ l for l in lines.splitlines() if l.startswith(' inet ') ] if not lines: return None toks = lines[0].split() diff --git a/ui/index.jsp b/ui/index.jsp index 8be1f714663..3fe04850c2a 100755 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -25,7 +25,7 @@ long milliseconds = new Date().getTime(); - Default Cloud.com styling of the site. This file contains the easiest portion of the site that can be styled to your companie's need such as logo, top navigation, and dialogs. --> - + diff --git a/ui/new/css/main.css b/ui/new/css/main.css index a4f239d1334..1c6ac42a7d4 100644 --- a/ui/new/css/main.css +++ b/ui/new/css/main.css @@ -1467,7 +1467,7 @@ a:visited { height:auto; float:left; margin:0 0 5px 10px; - padding:0; + padding:0 0 10px 0; list-style:none; } @@ -1479,7 +1479,7 @@ a:visited { color:#CCC; font-size:11px; font-weight:normal; - margin:6px 0 0 0; + margin:8px 0 0 0; padding:0; list-style:none; } @@ -1998,7 +1998,39 @@ a:visited { color:#a90000; } -.thanks box { - +.grid_header { + width:100%; + height:20px; + float:left; + background:url(../images/grid_headerbg.gif) repeat-x top left; + margin:0; + padding:0; } +.grid_header_title { + width:auto; + height:auto; + float:left; + margin:4px 0 0 10px; + display:inline; + color:#434343; + text-align:left; + font-weight:bold; + font-size:11px; + padding:0; +} + +.grid_actionbox { + width:33px; + height:15px; + float:right; + background:url(../images/gird_actions.gif) no-repeat top left; + margin:2px 10px 0 0; + padding:0; + cursor:pointer; + cursor:hand; +} + +.grid_actionbox:hover { + background:url(../images/gird_actions_hover.gif) no-repeat top left; +} \ No newline at end of file diff --git a/ui/new/images/gird_actions.gif b/ui/new/images/gird_actions.gif new file mode 100644 index 00000000000..18a377f5704 Binary files /dev/null and b/ui/new/images/gird_actions.gif differ diff --git a/ui/new/images/gird_actions_hover.gif b/ui/new/images/gird_actions_hover.gif new file mode 100644 index 00000000000..569f07550a7 Binary files /dev/null and b/ui/new/images/gird_actions_hover.gif differ diff --git a/ui/new/images/grid_headerbg.gif b/ui/new/images/grid_headerbg.gif new file mode 100644 index 00000000000..9004bfa474b Binary files /dev/null and b/ui/new/images/grid_headerbg.gif differ diff --git a/ui/new/jsp/tab_account.jsp b/ui/new/jsp/tab_account.jsp index a4b8c117648..c64d2ae9301 100644 --- a/ui/new/jsp/tab_account.jsp +++ b/ui/new/jsp/tab_account.jsp @@ -12,6 +12,14 @@ %> +
+ +

Account +

+