From 3752a4eb31bf53212c9088407999ba79eb75647b Mon Sep 17 00:00:00 2001 From: root Date: Thu, 28 Oct 2010 09:42:17 -0700 Subject: [PATCH] making the logic more robust, testing more corner cases, improving efficiency and changing the schema --- .../com/cloud/certificate/CertificateVO.java | 11 ++ .../cloud/certificate/dao/CertificateDao.java | 2 +- .../certificate/dao/CertificateDaoImpl.java | 10 +- server/src/com/cloud/api/BaseCmd.java | 2 +- .../commands/UploadCustomCertificateCmd.java | 14 +- .../consoleproxy/ConsoleProxyManagerImpl.java | 11 +- .../com/cloud/server/ManagementServer.java | 4 +- .../cloud/server/ManagementServerImpl.java | 123 ++++++++++-------- setup/db/create-schema.sql | 3 + 9 files changed, 107 insertions(+), 73 deletions(-) diff --git a/core/src/com/cloud/certificate/CertificateVO.java b/core/src/com/cloud/certificate/CertificateVO.java index 7bb0cf9b16d..bfa48d68ecb 100644 --- a/core/src/com/cloud/certificate/CertificateVO.java +++ b/core/src/com/cloud/certificate/CertificateVO.java @@ -36,6 +36,9 @@ public class CertificateVO { @Column(name="certificate",length=65535) private String certificate; + @Column(name="updated") + private String updated; + public CertificateVO() {} public Long getId() { @@ -48,4 +51,12 @@ public class CertificateVO { public void setCertificate(String certificate) { this.certificate = certificate; } + + public String getUpdated(){ + return this.updated; + } + + public void setUpdated(String updated){ + this.updated = updated; + } } diff --git a/core/src/com/cloud/certificate/dao/CertificateDao.java b/core/src/com/cloud/certificate/dao/CertificateDao.java index 192e1619307..138c6766c18 100644 --- a/core/src/com/cloud/certificate/dao/CertificateDao.java +++ b/core/src/com/cloud/certificate/dao/CertificateDao.java @@ -22,5 +22,5 @@ import com.cloud.certificate.CertificateVO; import com.cloud.utils.db.GenericDao; public interface CertificateDao extends GenericDao { - public Long persistCustomCertToDb(String certPath); + public Long persistCustomCertToDb(String certPath, CertificateVO cert); } diff --git a/core/src/com/cloud/certificate/dao/CertificateDaoImpl.java b/core/src/com/cloud/certificate/dao/CertificateDaoImpl.java index 6c2b4d846d8..20a002ff021 100644 --- a/core/src/com/cloud/certificate/dao/CertificateDaoImpl.java +++ b/core/src/com/cloud/certificate/dao/CertificateDaoImpl.java @@ -24,7 +24,7 @@ public class CertificateDaoImpl extends GenericDaoBase imp } @Override - public Long persistCustomCertToDb(String certPath){ + public Long persistCustomCertToDb(String certPath, CertificateVO cert){ BufferedInputStream f = null; String certStr = null; try @@ -33,10 +33,10 @@ public class CertificateDaoImpl extends GenericDaoBase imp f = new BufferedInputStream(new FileInputStream(certPath)); f.read(buffer); certStr = new String(buffer); - CertificateVO certRec = new CertificateVO(); - certRec.setCertificate(certStr); - this.persist(certRec); - return certRec.getId(); + cert.setCertificate(certStr); + cert.setUpdated("t"); + update(cert.getId(),cert); + return cert.getId(); } catch (FileNotFoundException e) { s_logger.warn("Unable to read the certificate: "+e); return new Long(0); diff --git a/server/src/com/cloud/api/BaseCmd.java b/server/src/com/cloud/api/BaseCmd.java index 8acc98ea263..8760124bbc0 100755 --- a/server/src/com/cloud/api/BaseCmd.java +++ b/server/src/com/cloud/api/BaseCmd.java @@ -80,7 +80,7 @@ public abstract class BaseCmd { public static final int NET_DELETE_LB_RULE_ERROR = 567; public static final int NET_CONFLICT_LB_RULE_ERROR = 568; public static final int NET_LIST_ERROR = 570; - + public static final int CUSTOM_CERT_UPDATE_ERROR = 571; public static final int STORAGE_RESOURCE_IN_USE = 580; public static final DateFormat INPUT_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); diff --git a/server/src/com/cloud/api/commands/UploadCustomCertificateCmd.java b/server/src/com/cloud/api/commands/UploadCustomCertificateCmd.java index ded2098874a..4e0b2fe782f 100644 --- a/server/src/com/cloud/api/commands/UploadCustomCertificateCmd.java +++ b/server/src/com/cloud/api/commands/UploadCustomCertificateCmd.java @@ -23,7 +23,7 @@ import com.cloud.api.ApiConstants; import com.cloud.api.BaseAsyncCmd; import com.cloud.api.Implementation; import com.cloud.api.Parameter; -import com.cloud.api.response.StatusResponse; +import com.cloud.api.response.CustomCertificateResponse; import com.cloud.event.EventTypes; import com.cloud.user.Account; @@ -40,14 +40,12 @@ public class UploadCustomCertificateCmd extends BaseAsyncCmd { return path; } - @Override @SuppressWarnings("unchecked") - public StatusResponse getResponse() { - Boolean status = (Boolean)getResponseObject(); - - StatusResponse response = new StatusResponse(); - response.setStatus(status); - response.setResponseName(getName()); + public CustomCertificateResponse getResponse() { + String updatedCpIdList = (String)getResponseObject(); + CustomCertificateResponse response = new CustomCertificateResponse(); + response.setResponseName(s_name); + response.setUpdatedConsoleProxyIdList(updatedCpIdList); return response; } diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 13c052b14d1..e952e5c9c55 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -2446,10 +2446,9 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach 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 certList = _certDao.listAll(); + CertificateVO cert = _certDao.listAll().get(0); - if(certList.size()>0){ - CertificateVO cert = certList.get(0);//there will only be 1 cert in db for now + if(cert.getUpdated().equals("t")){ String certStr = cert.getCertificate(); long proxyVmId = (cmd).getProxyVmId(); ConsoleProxyVO consoleProxy = _consoleProxyDao.findById(proxyVmId); @@ -2466,14 +2465,14 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach 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"); + s_logger.info("Successfully rebooted console proxy resource after custom certificate application for proxy:"+cmd.getProxyVmId()); return true; } } catch (AgentUnavailableException e) { - s_logger.warn("Unable to send update certificate command to the console proxy resource", e); + s_logger.warn("Unable to send update certificate command to the console proxy resource for proxy:"+cmd.getProxyVmId(), e); return false; } catch (OperationTimedoutException e) { - s_logger.warn("Unable to send update certificate command to the console proxy resource", e); + s_logger.warn("Unable to send update certificate command to the console proxy resource for proxy:"+cmd.getProxyVmId(), e); return false; } } diff --git a/server/src/com/cloud/server/ManagementServer.java b/server/src/com/cloud/server/ManagementServer.java index 9468e768280..76793379ad9 100755 --- a/server/src/com/cloud/server/ManagementServer.java +++ b/server/src/com/cloud/server/ManagementServer.java @@ -24,6 +24,8 @@ import java.util.List; import java.util.Map; import com.cloud.alert.AlertVO; +import com.cloud.api.ServerApiException; +import com.cloud.api.commands.AssignPortForwardingServiceCmd; import com.cloud.api.commands.CreateDomainCmd; import com.cloud.api.commands.CreateUserCmd; import com.cloud.api.commands.DeleteDomainCmd; @@ -1117,5 +1119,5 @@ public interface ManagementServer { */ String[] getHypervisors(ListHypervisorsCmd cmd); - boolean uploadCertificate(UploadCustomCertificateCmd cmd) throws ResourceAllocationException; + String uploadCertificate(UploadCustomCertificateCmd cmd) throws ServerApiException; } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index db2b6ad6395..1fbf97568a6 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -5865,58 +5865,79 @@ public class ManagementServerImpl implements ManagementServer { return event.getId(); } - @Override - 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 + @Override @DB + public String uploadCertificate(UploadCustomCertificateCmd cmd) throws ServerApiException{ + try + { + CertificateVO cert = _certDao.listAll().get(0); //always 1 record in db + + if(cert.getUpdated().equals("t")){ + if(s_logger.isDebugEnabled()) + s_logger.debug("A custom certificate already exists in the DB, will replace it with the new one being uploaded"); + }else{ + if(s_logger.isDebugEnabled()) + s_logger.debug("No custom certificate exists in the DB, will upload a new one"); + } + String certificatePath = cmd.getPath(); + CertificateVO lockedCert = _certDao.acquire(cert.getId()); + Long certVOId = _certDao.persistCustomCertToDb(certificatePath,lockedCert);//0 implies failure - if (certVOId!=null && certVOId!=0) - { - //certficate uploaded to db successfully - //get a list of all Console proxies from the cp table - List cpList = _consoleProxyDao.listAll(); - //get a list of all hosts in host table for type cp - List cpHosts = _hostDao.listByType(com.cloud.host.Host.Type.ConsoleProxy); - //create a hashmap for fast lookup - Map hostNameToHostIdMap = new HashMap(); - //updated console proxies list - List updatedCpList = new ArrayList(); - - for(HostVO cpHost : cpHosts){ - hostNameToHostIdMap.put(cpHost.getName(), cpHost.getId()); - } - - for(ConsoleProxyVO cp : cpList) - { - Long cpHostId = hostNameToHostIdMap.get(cp.getName());//there will always be a cphost for a cpvm - //now send a command to each console proxy - UpdateCertificateCommand certCmd = new UpdateCertificateCommand(_certDao.findById(certVOId).getCertificate()); - try { - Answer updateCertAns = _agentMgr.send(cpHostId, 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 update certificate command to the console proxy resource as agent is unavailable", e); - } catch (OperationTimedoutException e) { - s_logger.warn("Unable to send update certificate command to the console proxy resource as there was a timeout", e); - } - } - return true; - } - else - { - return false; - } + if (certVOId!=null && certVOId!=0) + { + //certficate uploaded to db successfully + //get a list of all Console proxies from the cp table + List cpList = _consoleProxyDao.listAll(); + if(cpList.size() == 0){ + throw new ServerApiException(BaseCmd.CUSTOM_CERT_UPDATE_ERROR, "Unable to find any console proxies in the system for certificate update"); + } + //get a list of all hosts in host table for type cp + List cpHosts = _hostDao.listByType(com.cloud.host.Host.Type.ConsoleProxy); + if(cpHosts.size() == 0){ + throw new ServerApiException(BaseCmd.CUSTOM_CERT_UPDATE_ERROR, "Unable to find any console proxy hosts in the system for certificate update"); + } + //create a hashmap for fast lookup + Map hostNameToHostIdMap = new HashMap(); + //updated console proxies id list + List updatedCpIdList = new ArrayList(); + for(HostVO cpHost : cpHosts){ + hostNameToHostIdMap.put(cpHost.getName(), cpHost.getId()); + } + + for(ConsoleProxyVO cp : cpList) + { + Long cpHostId = hostNameToHostIdMap.get(cp.getName()); + //now send a command to each console proxy + UpdateCertificateCommand certCmd = new UpdateCertificateCommand(_certDao.findById(certVOId).getCertificate()); + try { + Answer updateCertAns = _agentMgr.send(cpHostId, 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 + if(s_logger.isDebugEnabled()) + s_logger.debug("Successfully updated custom certificate on console proxy vm id:"+cp.getId()+" ,console proxy host id:"+cpHostId); + updatedCpIdList.add(cp.getId()); + } + } catch (AgentUnavailableException e) { + s_logger.warn("Unable to send update certificate command to the console proxy resource as agent is unavailable for console proxy vm id:"+cp.getId()+" ,console proxy host id:"+cpHostId, e); + } catch (OperationTimedoutException e) { + s_logger.warn("Unable to send update certificate command to the console proxy resource as there was a timeout for console proxy vm id:"+cp.getId()+" ,console proxy host id:"+cpHostId, e); + } + } + + _certDao.release(lockedCert.getId()); + return ("Updated:"+updatedCpIdList.size()+" out of:"+cpList.size()); + } + else + { + return null; + } + } catch (Exception e) { + s_logger.warn("Failed to persist custom certificate to the db"); + } + return null; } @Override diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 9db4f587e77..1f52f94caa7 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -134,9 +134,12 @@ CREATE TABLE `cloud`.`account_network_ref` ( CREATE TABLE `cloud`.`certificate` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `certificate` text COMMENT 'the actual custom certificate being stored in the db', + `updated` varchar(1) COMMENT 'status of the certificate', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +INSERT INTO `cloud`.`certificate` (id,certificate,updated) VALUES ('1',null,'f'); + CREATE TABLE `cloud`.`nics` ( `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id', `instance_id` bigint unsigned NOT NULL COMMENT 'vm instance id',