Merge branch 'master' of ssh://git.cloud.com/var/lib/git/cloudstack-oss

This commit is contained in:
will 2010-10-26 15:15:21 -07:00
commit 4e544ce0f9
21 changed files with 312 additions and 103 deletions

View File

@ -113,29 +113,29 @@ public class ConsoleProxyResource extends ServerResourceBase implements ServerRe
String certificate = cmd.getCertificate();
//write the cert to /etc/cloud/consoleproxy/cert/
String strDirectoy ="/etc/cloud/consoleproxy/cert/";
boolean dirCreated = (new File(strDirectoy)).mkdir();
if (dirCreated) {
s_logger.info("Directory: " + strDirectoy + " created");
//copy cert to the dir
try {
boolean dirCreated = false;
String strDirectoy = "/etc/cloud/consoleproxy/cert/";
dirCreated = (new File(strDirectoy)).mkdirs();
if (dirCreated)
{
if(s_logger.isDebugEnabled())
s_logger.info("Directory: " + strDirectoy + " created");
//copy cert to the dir
FileWriter fstream = new FileWriter("/etc/cloud/consoleproxy/cert/customcert");
BufferedWriter out = new BufferedWriter(fstream);
out.write(certificate);
//Close the output stream
out.close();
}catch (Exception e){
s_logger.warn("Unable to write file to /etc/cloud/consoleproxy/cert/ on console proxy", e);
}
success = true;
}
success = true;
return new Answer(cmd, success, "Cert string in the console proxy resource status:");
return new Answer(cmd, success, "Custom certificate update required status");
}catch (Exception e)
{
s_logger.error("Unable to read the cert string in console proxy resource");
s_logger.error("Unable to read the cert string in console proxy resource",e);
success = false;
}
return new Answer(cmd, success, "Cert string in the console proxy resource status:");
return new Answer(cmd, success, "Custom certificate response from the updatecertificate flow");
}
protected Answer execute(final CheckConsoleProxyLoadCommand cmd) {

View File

@ -207,6 +207,13 @@
</zip>
</target>
<target name="package-tools" depends="-init-package">
<delete file="${publish.dir}/cloudapitools.zip" />
<zip destfile="${publish.dir}/cloudapitools.zip" compress="false">
<zipfileset dir="${tools.dist.dir}" filemode="555" />
</zip>
</target>
<target name="clean-packages">
<delete>
<fileset dir="${dist.dir}" includes="*.zip" />

View File

@ -135,7 +135,9 @@ public interface HostDao extends GenericDao<HostVO, Long> {
long getNextSequence(long hostId);
void loadDetails(HostVO host);
void loadDetails(HostVO host);
HostVO findConsoleProxyHost(String name, Type type);
}

View File

@ -79,6 +79,7 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
protected final SearchBuilder<HostVO> UnmanagedDirectConnectSearch;
protected final SearchBuilder<HostVO> MaintenanceCountSearch;
protected final SearchBuilder<HostVO> ClusterSearch;
protected final SearchBuilder<HostVO> ConsoleProxyHostSearch;
protected final Attribute _statusAttr;
protected final Attribute _msIdAttr;
@ -154,6 +155,11 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
ClusterSearch = createSearchBuilder();
ClusterSearch.and("cluster", ClusterSearch.entity().getClusterId(), SearchCriteria.Op.EQ);
ClusterSearch.done();
ConsoleProxyHostSearch = createSearchBuilder();
ConsoleProxyHostSearch.and("name", ConsoleProxyHostSearch.entity().getName(), SearchCriteria.Op.EQ);
ConsoleProxyHostSearch.and("type", ConsoleProxyHostSearch.entity().getType(), SearchCriteria.Op.EQ);
ConsoleProxyHostSearch.done();
PodSearch = createSearchBuilder();
PodSearch.and("pod", PodSearch.entity().getPodId(), SearchCriteria.Op.EQ);
@ -442,7 +448,20 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
SearchCriteria<HostVO> sc = DcSearch.create("dc", dcId);
return listBy(sc);
}
@Override
public HostVO findConsoleProxyHost(String name, Type type) {
SearchCriteria<HostVO> sc = ConsoleProxyHostSearch.create();
sc.setParameters("name", name);
sc.setParameters("type", type);
List<HostVO>hostList = listBy(sc);
if(hostList==null || hostList.size() == 0)
return null;
else
return hostList.get(0);
}
public List<HostVO> listByHostPod(long podId) {
SearchCriteria<HostVO> sc = PodSearch.create("pod", podId);
return listBy(sc);

View File

@ -36,6 +36,7 @@ import com.cloud.configuration.ConfigurationManager;
import com.cloud.consoleproxy.ConsoleProxyManager;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.network.DomainRouterService;
import com.cloud.network.NetworkManager;
import com.cloud.network.security.NetworkGroupManager;
@ -154,6 +155,8 @@ public class ApiDispatcher {
throw new ServerApiException(BaseCmd.PARAM_ERROR, cause.getMessage());
} else if (cause instanceof PermissionDeniedException) {
throw new ServerApiException(BaseCmd.ACCOUNT_ERROR, cause.getMessage());
} else if (cause instanceof ResourceAllocationException){
throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, cause.getMessage());
}
s_logger.warn("Exception executing method " + methodName + " for command " + cmd.getClass().getSimpleName(), ite);
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Unable to execute method " + methodName + " for command " + cmd.getClass().getSimpleName() + ", internal error in the implementation.");

View File

@ -19,13 +19,15 @@ package com.cloud.api.commands;
import org.apache.log4j.Logger;
import com.cloud.api.BaseCmd;
import com.cloud.api.BaseAsyncCmd;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.response.StatusResponse;
import com.cloud.event.EventTypes;
import com.cloud.user.Account;
@Implementation(method="uploadCertificate")
public class UploadCustomCertificateCmd extends BaseCmd {
public class UploadCustomCertificateCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(UploadCustomCertificateCmd.class.getName());
private static final String s_name = "uploadcustomcertificateresponse";
@ -37,11 +39,7 @@ public class UploadCustomCertificateCmd extends BaseCmd {
return path;
}
@Override
public String getName() {
return s_name;
}
@Override @SuppressWarnings("unchecked")
public StatusResponse getResponse() {
Boolean status = (Boolean)getResponseObject();
@ -51,4 +49,29 @@ public class UploadCustomCertificateCmd extends BaseCmd {
response.setResponseName(getName());
return response;
}
@Override
public String getEventType() {
return EventTypes.EVENT_VOLUME_CREATE;
}
@Override
public String getEventDescription() {
return ("Uploading custom certificate to the db, and applying it to the cpvm");
}
@Override
public String getName() {
return s_name;
}
public static String getResultObjectName() {
return "volume";
}
@Override
public long getAccountId() {
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
}

View File

@ -236,14 +236,11 @@ public class ApiXmlDocReader {
}
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -129,7 +129,6 @@ public class ApiXmlDocWriter {
// //Get fields from superclass
Class<?> superClass = clas.getSuperclass();
String superName = superClass.getName();
// while (BaseCmd.class.isAssignableFrom(superClass) && !superClass.getName().equals(BaseCmd.class.getName())) {
if (!superName.equals(BaseCmd.class.getName()) && !superName.equals(BaseAsyncCmd.class.getName()) && !superName.equals(BaseAsyncCreateCmd.class.getName())) {
Field[] superClassFields = superClass.getDeclaredFields();
if (superClassFields != null) {
@ -140,8 +139,6 @@ public class ApiXmlDocWriter {
}
superClass = superClass.getSuperclass();
}
// }
for (Field f : fields) {
Parameter parameterAnnotation = f.getAnnotation(Parameter.class);

View File

@ -34,6 +34,7 @@ import com.cloud.agent.api.ConsoleProxyLoadReportCommand;
import com.cloud.agent.api.GetVncPortAnswer;
import com.cloud.agent.api.GetVncPortCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupProxyCommand;
import com.cloud.agent.api.StopCommand;
import com.cloud.api.ServerApiException;
import com.cloud.api.commands.DestroyConsoleProxyCmd;
@ -54,9 +55,10 @@ import com.cloud.utils.component.Inject;
import com.cloud.vm.ConsoleProxyVO;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.VirtualMachineName;
import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.dao.ConsoleProxyDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
@ -74,13 +76,13 @@ public class AgentBasedConsoleProxyManager implements ConsoleProxyManager, Virtu
@Inject
private VMInstanceDao _instanceDao;
private ConsoleProxyListener _listener;
protected int _consoleProxyUrlPort = ConsoleProxyManager.DEFAULT_PROXY_URL_PORT;
protected int _consoleProxyPort = ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT;
protected boolean _sslEnabled = false;
@Inject
AgentManager _agentMgr;
@Inject
protected ConsoleProxyDao _cpDao;
public int getVncPort(VMInstanceVO vm) {
if (vm.getHostId() == null) {
return -1;
@ -324,5 +326,11 @@ public class AgentBasedConsoleProxyManager implements ConsoleProxyManager, Virtu
@Override
public boolean destroyConsoleProxy(DestroyConsoleProxyCmd cmd) throws ServerApiException {
return false;
}
}
@Override
public boolean applyCustomCertToNewProxy(StartupProxyCommand cmd) {
// TODO Auto-generated method stub
return false;
}
}

View File

@ -7,6 +7,7 @@ import com.cloud.agent.api.AgentControlAnswer;
import com.cloud.agent.api.ConsoleAccessAuthenticationCommand;
import com.cloud.agent.api.ConsoleProxyLoadReportCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupProxyCommand;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
@ -16,4 +17,5 @@ public interface AgentHook {
void onAgentConnect(HostVO host, StartupCommand cmd);
public void onAgentDisconnect(long agentId, Status state);
boolean applyCustomCertToNewProxy(StartupProxyCommand cmd);
}

View File

@ -25,6 +25,7 @@ import com.cloud.agent.api.Command;
import com.cloud.agent.api.ConsoleAccessAuthenticationCommand;
import com.cloud.agent.api.ConsoleProxyLoadReportCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupProxyCommand;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
@ -66,6 +67,10 @@ public class ConsoleProxyListener implements Listener {
@Override
public void processConnect(HostVO host, StartupCommand cmd) {
_proxyMgr.onAgentConnect(host, cmd);
if (cmd instanceof StartupProxyCommand) {
_proxyMgr.applyCustomCertToNewProxy((StartupProxyCommand)cmd);
}
}
@Override

View File

@ -56,9 +56,11 @@ import com.cloud.agent.api.Start2Command;
import com.cloud.agent.api.StartConsoleProxyAnswer;
import com.cloud.agent.api.StartConsoleProxyCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupProxyCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.proxy.ConsoleProxyLoadAnswer;
import com.cloud.agent.api.proxy.UpdateCertificateCommand;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.agent.api.to.VirtualMachineTO.SshMonitor;
@ -70,13 +72,15 @@ import com.cloud.async.AsyncJobExecutor;
import com.cloud.async.AsyncJobManager;
import com.cloud.async.AsyncJobVO;
import com.cloud.async.BaseAsyncJobExecutor;
import com.cloud.certificate.CertificateVO;
import com.cloud.certificate.dao.CertificateDao;
import com.cloud.cluster.ClusterManager;
import com.cloud.configuration.Config;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.VlanVO;
import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.dc.dao.VlanDao;
@ -97,8 +101,8 @@ import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.ha.HighAvailabilityManager;
import com.cloud.host.Host;
import com.cloud.host.Host.Type;
import com.cloud.host.HostVO;
import com.cloud.host.Host.Type;
import com.cloud.host.dao.HostDao;
import com.cloud.info.ConsoleProxyConnectionInfo;
import com.cloud.info.ConsoleProxyInfo;
@ -109,10 +113,10 @@ import com.cloud.info.RunningHostInfoAgregator;
import com.cloud.info.RunningHostInfoAgregator.ZoneHostInfo;
import com.cloud.maid.StackMaid;
import com.cloud.network.IpAddrAllocator;
import com.cloud.network.IpAddrAllocator.networkInfo;
import com.cloud.network.Network.TrafficType;
import com.cloud.network.NetworkConfigurationVO;
import com.cloud.network.NetworkManager;
import com.cloud.network.IpAddrAllocator.networkInfo;
import com.cloud.network.Network.TrafficType;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.offering.NetworkOffering;
import com.cloud.offerings.NetworkOfferingVO;
@ -124,9 +128,9 @@ import com.cloud.storage.GuestOSVO;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.VMTemplateHostVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplateHostDao;
@ -155,12 +159,12 @@ import com.cloud.vm.NicProfile;
import com.cloud.vm.State;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.Event;
import com.cloud.vm.VirtualMachineGuru;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.VirtualMachineName;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.VmManager;
import com.cloud.vm.VirtualMachine.Event;
import com.cloud.vm.dao.ConsoleProxyDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.google.gson.Gson;
@ -229,12 +233,12 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach
private HostDao _hostDao;
@Inject
private ConfigurationDao _configDao;
@Inject
private CertificateDao _certDao;
@Inject
private VMInstanceDao _instanceDao;
@Inject
private AccountDao _accountDao;
@Inject private VMTemplateHostDao _vmTemplateHostDao;
@Inject private AgentManager _agentMgr;
@Inject private StorageManager _storageMgr;
@ -2432,4 +2436,57 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach
public boolean processDeploymentResult(Commands cmds, ConsoleProxyVO proxy, VirtualMachineProfile profile, DeployDestination dest) {
return true;
}
@Override
public boolean applyCustomCertToNewProxy(StartupProxyCommand cmd){
//this is the case for updating cust cert on each new starting proxy, if such cert exists
//get cert from db
List<CertificateVO> certList = _certDao.listAll();
if(certList.size()>0){
CertificateVO cert = certList.get(0);//there will only be 1 cert in db for now
String certStr = cert.getCertificate();
long proxyVmId = ((StartupProxyCommand)cmd).getProxyVmId();
ConsoleProxyVO consoleProxy = _consoleProxyDao.findById(proxyVmId);
//find corresponding host
if(consoleProxy!=null){
HostVO consoleProxyHost = _hostDao.findConsoleProxyHost(consoleProxy.getName(), Type.ConsoleProxy);
//now send a command to console proxy
UpdateCertificateCommand certCmd = new UpdateCertificateCommand(certStr);
try {
Answer updateCertAns = _agentMgr.send(consoleProxyHost.getId(), certCmd);
if(updateCertAns.getResult() == true)
{
//we have the cert copied over on cpvm
long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_PROXY_REBOOT, "rebooting console proxy with Id: "+consoleProxy.getId());
rebootProxy(consoleProxy.getId(), eventId);
//when cp reboots, the context will be reinit with the new cert
s_logger.info("Successfully rebooted console proxy resource after custom certificate application");
return true;
}
} catch (AgentUnavailableException e) {
s_logger.warn("Unable to send update certificate command to the console proxy resource", e);
return false;
} catch (OperationTimedoutException e) {
s_logger.warn("Unable to send update certificate command to the console proxy resource", e);
return false;
}
}
}else{
return false;//no cert
}
return false;
}
private Long saveScheduledEvent(Long userId, Long accountId, String type, String description)
{
EventVO event = new EventVO();
event.setUserId(userId);
event.setAccountId(accountId);
event.setType(type);
event.setState(EventState.Scheduled);
event.setDescription("Scheduled async job for "+description);
event = _eventDao.persist(event);
return event.getId();
}
}

View File

@ -1219,5 +1219,5 @@ public interface ManagementServer {
*/
String[] getHypervisors(ListHypervisorsCmd cmd);
boolean uploadCertificate(UploadCustomCertificateCmd cmd);
boolean uploadCertificate(UploadCustomCertificateCmd cmd) throws ResourceAllocationException;
}

View File

@ -26,6 +26,7 @@ import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@ -148,6 +149,7 @@ import com.cloud.async.dao.AsyncJobDao;
import com.cloud.async.executor.ExtractJobResultObject;
import com.cloud.capacity.CapacityVO;
import com.cloud.capacity.dao.CapacityDao;
import com.cloud.certificate.CertificateVO;
import com.cloud.certificate.dao.CertificateDao;
import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager;
@ -174,6 +176,7 @@ import com.cloud.dc.dao.PodVlanMapDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.EventState;
import com.cloud.event.EventTypes;
import com.cloud.event.EventUtils;
import com.cloud.event.EventVO;
@ -6931,41 +6934,64 @@ public class ManagementServerImpl implements ManagementServer {
}
return version;
}
private Long saveScheduledEvent(Long userId, Long accountId, String type, String description)
{
EventVO event = new EventVO();
event.setUserId(userId);
event.setAccountId(accountId);
event.setType(type);
event.setState(EventState.Scheduled);
event.setDescription("Scheduled async job for "+description);
event = _eventDao.persist(event);
return event.getId();
}
@Override
public boolean uploadCertificate(UploadCustomCertificateCmd cmd) {
public boolean uploadCertificate(UploadCustomCertificateCmd cmd) throws ResourceAllocationException {
//limit no.of certs uploaded to 1
if(_certDao.listAll().size()>0){
throw new ResourceAllocationException("There is already a custom certificate in the db");
}
String certificatePath = cmd.getPath();
Long certVOId = _certDao.persistCustomCertToDb(certificatePath);//0 implies failure
if (certVOId!=null && certVOId!=0) {
//certficate uploaded to db successfully
if (certVOId!=null && certVOId!=0)
{
//certficate uploaded to db successfully
//get a list of all Console proxies from the cp table
List<ConsoleProxyVO> cpList = _consoleProxyDao.listAll();
//get a list of all hosts from host table
List<HostVO> hosts = _hostDao.listAll();
List<HostVO> consoleProxyList = new ArrayList<HostVO>();
//find the console proxies, and send the command to them
for(HostVO host : hosts) {
if(host.getType().equals(com.cloud.host.Host.Type.ConsoleProxy)){
consoleProxyList.add(host);
}
}
for(HostVO consoleProxy : consoleProxyList){
for(ConsoleProxyVO cp : cpList)
{
HostVO cpHost = _hostDao.findConsoleProxyHost(cp.getName(), com.cloud.host.Host.Type.ConsoleProxy);
//now send a command to each console proxy
UpdateCertificateCommand certCmd = new UpdateCertificateCommand(_certDao.findById(certVOId).getCertificate());
try {
Answer updateCertAns = _agentMgr.send(consoleProxy.getId(), certCmd);
Answer updateCertAns = _agentMgr.send(cpHost.getId(), certCmd);
if(updateCertAns.getResult() == true)
{
//we have the cert copied over on cpvm
long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_PROXY_REBOOT, "rebooting console proxy with Id: "+cp.getId());
_consoleProxyMgr.rebootProxy(cp.getId(), eventId);
//when cp reboots, the context will be reinit with the new cert
}
} catch (AgentUnavailableException e) {
s_logger.warn("Unable to send command to the console proxy resource", e);
s_logger.warn("Unable to send update certificate command to the console proxy resource", e);
} catch (OperationTimedoutException e) {
s_logger.warn("Unable to send command to the console proxy resource", e);
s_logger.warn("Unable to send update certificate command to the console proxy resource", e);
}
}
return true;
}
else
{
return false;
}
return false;
}
@Override

View File

@ -2487,9 +2487,12 @@ public class StorageManagerImpl implements StorageManager {
// Check that the volume is stored on shared storage
if (!volumeOnSharedStoragePool(volume)) {
throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool.");
}
// NOTE: We used to ensure the volume is on shared storage before deleting. However, this seems like an unnecessary check since all we allow
// is deleting a detached volume. Is there a technical reason why the volume has to be on shared storage? If so, uncomment this...otherwise,
// just delete the detached volume regardless of storage pool.
// if (!volumeOnSharedStoragePool(volume)) {
// throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool.");
// }
// Check that the volume is not currently attached to any VM
if (volume.getInstanceId() != null) {

View File

@ -2006,6 +2006,7 @@ a:hover.search_button {
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;
@ -2251,6 +2252,25 @@ a:hover.search_button {
color:#999;
}
.midmenu_emptymsgbox {
width:220px;
height:auto;
float:left;
background:#d4d4d4 url(../images/midmenu_emptymsg.gif) repeat-x top left;
margin:0 0 0 0;
padding:0;
}
.midmenu_emptymsgbox p{
width:200px;
height:auto;
float:left;
color:#666;
font-size:11px;
font-weight:normal;
margin:0 0 0 0;
padding:0;
}
.main_contentarea_with_midmenu {
width:auto;
@ -2448,6 +2468,30 @@ a:hover.search_button {
color:#333;
font-size:11px;
}
.grid_row_cell .error_text {
width:92%;
height:16px;
float:left;
margin:0 0 0 10px;
display:inline;
padding:0 0 0 2px;
border:1px solid #999;
background:#ffe5e5;
color:#333;
font-size:11px;
}
.errormsg {
width:80%;
height:auto;
float:left;
margin:3px 0 0 10px;
display:inline;
padding:0 0 0 2px;
color:#a90000;
font-size:11px;
font-weight:normal;
}
.grid_row_cell .select {
width:92%;
@ -3043,7 +3087,7 @@ a:hover.search_button {
height:auto;
float:left;
position:absolute;
background:#FFF url(../images/midmenu_hover.gif) repeat top left;
background:#FFF repeat top left;
border:1px solid #CCC;
top:18px;
right:1px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

View File

@ -316,7 +316,7 @@ long milliseconds = new Date().getTime();
<!-- Mid Menu starts here-->
<div class="midmenu_panel" id="middle_menu">
<div class="midmenu_box" id="midmenu_container">
<div class="midmenu_emptymsgbox"><p>No Items Available</p></div>
</div>
</div>
<!-- Mid Menu ends here-->

View File

@ -166,15 +166,15 @@
</div>
<div class="grid_rows even" id="create_port_forwarding_row">
<div class="grid_row_cell" style="width: 15%;">
<input id="public_port" class="text" style="width: 90%;" type="text" />
<input id="public_port" class="text" style="width: 70%;" type="text" />
<div id="public_port_errormsg" class="errormsg" style="display: none;">Error msg will appear here</div>
</div>
<div class="grid_row_cell" style="width: 15%;">
<input id="private_port" class="text" style="width: 90%;" type="text" />
<input id="private_port" class="text" style="width: 70%;" type="text" />
<div id="private_port_errormsg" class="errormsg" style="display: none;">Error msg will appear here</div>
</div>
<div class="grid_row_cell" style="width: 15%;">
<select class="select" id="protocol">
<select class="select" id="protocol" style="width:70%;">
<option value="TCP">TCP</option>
<option value="UDP">UDP</option>
</select>
@ -220,19 +220,19 @@
</div>
<div class="grid_rows even" id="create_load_balancer_row">
<div class="grid_row_cell" style="width: 25%;">
<input id="name" class="text" style="width: 90%;" type="text" />
<input id="name" class="text" style="width: 70%;" type="text" />
<div id="name_errormsg" class="errormsg" style="display: none;">Error msg will appear here</div>
</div>
<div class="grid_row_cell" style="width: 15%;">
<input id="public_port" class="text" style="width: 90%;" type="text" />
<input id="public_port" class="text" style="width: 70%;" type="text" />
<div id="public_port_errormsg" class="errormsg" style="display: none;">Error msg will appear here</div>
</div>
<div class="grid_row_cell" style="width: 15%;">
<input id="private_port" class="text" style="width: 90%;" type="text" />
<input id="private_port" class="text" style="width: 70%;" type="text" />
<div id="private_port_errormsg" class="errormsg" style="display: none;">Error msg will appear here</div>
</div>
<div class="grid_row_cell" style="width: 15%;">
<select id="algorithm_select" class="select" style="width: 90%;">
<select id="algorithm_select" class="select" style="width: 70%;">
<option value="roundrobin">roundrobin</option>
<option value="leastconn">leastconn</option>
<option value="source">source</option>

View File

@ -191,8 +191,7 @@ function clusterJSONToTreeNode(json, $clusterNode) {
}
//$menuItem1 is either $leftmenuItem1 or $midmenuItem1
function showPage($pageToShow, $menuItem1) {
clearMiddleMenu();
function showPage($pageToShow, $menuItem1) {
if($pageToShow.length == 0) { //resource.jsp is not loaded in right panel
$("#right_panel").load("jsp/resource.jsp", function(){
showPage2($($pageToShow.selector), $menuItem1); //$pageToShow is still empty (i.e. $pageToShow.length == 0), So, select the element again.
@ -223,11 +222,16 @@ function showPage2($pageToShow, $menuItem1) {
$pageToShow.data("jsonObj", jsonObj);
}
if($pageToShow.attr("id") == "resource_page") {
if($pageToShow.attr("id") == "resource_page") {
clearMiddleMenu();
hideMiddleMenu();
initAddZoneButton($("#midmenu_add_link"));
initDialog("dialog_add_zone");
}
else if($pageToShow.attr("id") == "zone_page") {
else if($pageToShow.attr("id") == "zone_page") {
hideMiddleMenu();
initAddPodButton($("#midmenu_add_link"));
initAddVLANButton($("#midmenu_add2_link"));
initAddSecondaryStorageButton($("#midmenu_add3_link"));
@ -249,11 +253,12 @@ function showPage2($pageToShow, $menuItem1) {
//var afterSwitchFnArray = [afterSwitchToDetailsTab, afterSwitchToNetworkTab, afterSwitchToSecondaryStorageTab];
switchBetweenDifferentTabs(tabArray, tabContentArray);
$zonePage.find("#tab_details").click();
hideMiddleMenu();
zoneJsonToRightPanel($menuItem1);
}
else if($pageToShow.attr("id") == "pod_page") {
else if($pageToShow.attr("id") == "pod_page") {
hideMiddleMenu();
initAddHostButton($("#midmenu_add_link"));
initAddPrimaryStorageButton($("#midmenu_add2_link"));
@ -264,21 +269,22 @@ function showPage2($pageToShow, $menuItem1) {
if (getHypervisorType() == 'kvm')
$("#dialog_add_pool").find("#add_pool_protocol").empty().html('<option value="nfs">NFS</option>');
bindEventHandlerToDialogAddPool();
showMiddleMenu();
podJsonToRightPanel($menuItem1);
var podId = jsonObj.id;
$("#midmenu_container").empty();
listMidMenuItems2(("listHosts&type=Routing&podid="+podId), "listhostsresponse", "host", hostToMidmenu, hostToRightPanel, hostGetMidmenuId, false, false);
listMidMenuItems2(("listStoragePools&podid="+podId), "liststoragepoolsresponse", "storagepool", primarystorageToMidmenu, primarystorageToRightPanel, primarystorageGetMidmenuId, false, false);
//var podId = jsonObj.id;
//$("#midmenu_container").empty();
//listMidMenuItems2(("listHosts&type=Routing&podid="+podId), "listhostsresponse", "host", hostToMidmenu, hostToRightPanel, hostGetMidmenuId, false, false);
//listMidMenuItems2(("listStoragePools&podid="+podId), "liststoragepoolsresponse", "storagepool", primarystorageToMidmenu, primarystorageToRightPanel, primarystorageGetMidmenuId, false, false);
}
else if($pageToShow.attr("id") == "cluster_page") {
clearMiddleMenu();
showMiddleMenu();
$("#midmenu_add_link").unbind("click").hide();
$("#midmenu_add2_link").unbind("click").hide();
$("#midmenu_add3_link").unbind("click").hide();
showMiddleMenu();
$("#midmenu_add3_link").unbind("click").hide();
clusterJsonToRightPanel($menuItem1);
var clusterId = jsonObj.id;
@ -1274,9 +1280,10 @@ function initAddHostButton($midmenuAddLink1) {
var password = trim($thisDialog.find("#host_password").val());
array1.push("&password="+encodeURIComponent(password));
var newClusterName;
if(clusterRadio == "new_cluster_radio") {
var newClusterName = trim($thisDialog.find("#new_cluster_name").val());
newClusterName = trim($thisDialog.find("#new_cluster_name").val());
array1.push("&clustername="+todb(newClusterName));
}
else if(clusterRadio == "existing_cluster_radio") {
@ -1304,6 +1311,7 @@ function initAddHostButton($midmenuAddLink1) {
$thisDialog.find("#spinning_wheel").hide();
$thisDialog.dialog("close");
showMiddleMenu();
var $midmenuItem1 = $("#midmenu_item").clone();
$("#midmenu_container").append($midmenuItem1.fadeIn("slow"));
var items = json.addhostresponse.host;
@ -1319,13 +1327,16 @@ function initAddHostButton($midmenuAddLink1) {
}
}
if(clusterRadio == "new_cluster_radio")
$thisDialog.find("#new_cluster_name").val("");
refreshClusterUnderPod($("#pod_" + podObj.id));
if(clusterRadio == "new_cluster_radio") {
refreshClusterUnderPod($("#pod_" + podObj.id), newClusterName);
$thisDialog.find("#new_cluster_name").val("");
}
},
error: function(XMLHttpResponse) {
refreshClusterUnderPod($("#pod_" + podObj.id));
if(clusterRadio == "new_cluster_radio") {
refreshClusterUnderPod($("#pod_" + podObj.id), newClusterName);
$thisDialog.find("#new_cluster_name").val(""); //even AddHost fails, new cluster is still created. So, we clean up new cluster field to avoid the same one gets created twice.
}
handleErrorInDialog(XMLHttpResponse, $thisDialog);
}
});
@ -1338,7 +1349,7 @@ function initAddHostButton($midmenuAddLink1) {
});
}
function refreshClusterUnderPod($podNode) {
function refreshClusterUnderPod($podNode, newClusterName) {
var podId = $podNode.data("podId");
$.ajax({
data: createURL("command=listClusters&podid="+podId+maxPageSize),
@ -1349,9 +1360,14 @@ function refreshClusterUnderPod($podNode) {
var container = $podNode.find("#clusters_container").empty();
if (items != null && items.length > 0) {
for (var i = 0; i < items.length; i++) {
var clusterTemplate = $("#leftmenu_cluster_node_template").clone(true);
clusterJSONToTreeNode(items[i], clusterTemplate);
container.append(clusterTemplate.show());
var $clusterNode = $("#leftmenu_cluster_node_template").clone(true);
var item = items[i];
clusterJSONToTreeNode(item, $clusterNode);
container.append($clusterNode.show());
if(newClusterName != null && fromdb(item.name) == newClusterName) {
$clusterNode.find("#cluster_name").click();
}
}
$podNode.find("#pod_arrow").removeClass("white_nonexpanded_close").addClass("expanded_open");
$podNode.find("#pod_content").show();

View File

@ -959,7 +959,7 @@ function showStorageTab(domainId, targetTab) {
switch (linkAction) {
case "volume_action_delete" :
//check if this volume is attached to a virtual machine. If yes, can't be deleted.
if(vmname != null && (vmname != "" || vmname != "none")) {
if(vmname != null && vmname != "" && vmname != "none") {
$("#dialog_alert").html("<p>This volume is attached to virtual machine " + vmname + " and can't be deleted.</p>")
$("#dialog_alert").dialog("open");
return;