From 3e59707dd240c9b49836aee0d9ce510c760947f1 Mon Sep 17 00:00:00 2001 From: "Ragnar B. Johannsson" Date: Wed, 12 Jan 2011 16:32:36 +0000 Subject: [PATCH] Added user_vm_details table and corresponding access objects. Moved saved encrypted passwds for getVMPassword API cmd to this new table. Removed SSH keypair id from UserVm - only public key is needed. --- api/src/com/cloud/uservm/UserVm.java | 4 - core/src/com/cloud/vm/UserVmDetailVO.java | 67 ++++++++++++++++ core/src/com/cloud/vm/UserVmVO.java | 47 +---------- .../DefaultComponentLibrary.java | 3 + .../cloud/server/ManagementServerImpl.java | 14 +++- .../src/com/cloud/vm/UserVmManagerImpl.java | 13 +-- .../com/cloud/vm/dao/UserVmDetailsDao.java | 16 ++++ .../cloud/vm/dao/UserVmDetailsDaoImpl.java | 80 +++++++++++++++++++ setup/db/create-index-fk.sql | 2 + setup/db/create-schema.sql | 11 ++- 10 files changed, 198 insertions(+), 59 deletions(-) create mode 100644 core/src/com/cloud/vm/UserVmDetailVO.java create mode 100644 server/src/com/cloud/vm/dao/UserVmDetailsDao.java create mode 100644 server/src/com/cloud/vm/dao/UserVmDetailsDaoImpl.java diff --git a/api/src/com/cloud/uservm/UserVm.java b/api/src/com/cloud/uservm/UserVm.java index 9f7096c4b56..61a839d7815 100755 --- a/api/src/com/cloud/uservm/UserVm.java +++ b/api/src/com/cloud/uservm/UserVm.java @@ -69,9 +69,5 @@ public interface UserVm extends VirtualMachine, ControlledEntity { void setUserData(String userData); - String getEncryptedPassword(); - - Long getSSHKeyPairId(); - String getSSHPublicKey(); } diff --git a/core/src/com/cloud/vm/UserVmDetailVO.java b/core/src/com/cloud/vm/UserVmDetailVO.java new file mode 100644 index 00000000000..cb574c57337 --- /dev/null +++ b/core/src/com/cloud/vm/UserVmDetailVO.java @@ -0,0 +1,67 @@ +package com.cloud.vm; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name="user_vm_details") +public class UserVmDetailVO { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="vm_id") + private long vmId; + + @Column(name="name") + private String name; + + @Column(name="value") + private String value; + + public UserVmDetailVO() {} + + public UserVmDetailVO(long vmId, String name, String value) { + this.vmId = vmId; + this.name = name; + this.value = value; + } + + public long getId() { + return id; + } + + public long getVmId() { + return vmId; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public void setId(long id) { + this.id = id; + } + + public void setVmId(long vmId) { + this.vmId = vmId; + } + + public void setName(String name) { + this.name = name; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/core/src/com/cloud/vm/UserVmVO.java b/core/src/com/cloud/vm/UserVmVO.java index b0cf27361b2..d79cec6d3b6 100755 --- a/core/src/com/cloud/vm/UserVmVO.java +++ b/core/src/com/cloud/vm/UserVmVO.java @@ -64,12 +64,6 @@ public class UserVmVO extends VMInstanceVO implements UserVm { @Column(name="display_name", updatable=true, nullable=true) private String displayName; - @Column(name="encrypted_password", updatable=true, nullable=true) - private String encryptedPassword; - - @Column(name="ssh_keypair_id", updatable=true, nullable=true) - private Long sshKeyPairId; - @Column(name="ssh_public_key", updatable=true, nullable=true) private String sshPublicKey; @@ -91,24 +85,6 @@ public class UserVmVO extends VMInstanceVO implements UserVm { public void setSSHPublicKey(String publicKey) { this.sshPublicKey = publicKey; } - - @Override - public String getEncryptedPassword() { - return encryptedPassword; - } - - @Override - public Long getSSHKeyPairId() { - return sshKeyPairId; - } - - public void setEncryptedPassword(String encryptedPassword) { - this.encryptedPassword = encryptedPassword; - } - - public void setSSHKeyPairId(Long sshKeyPairId) { - this.sshKeyPairId = sshKeyPairId; - } @Override public String getGuestIpAddress() { @@ -181,10 +157,13 @@ public class UserVmVO extends VMInstanceVO implements UserVm { long domainId, long accountId, long serviceOfferingId, - String userData, String name) { + String userData, + String name, + String sshPublicKey) { super(id, serviceOfferingId, name, instanceName, Type.User, templateId, guestOsId, domainId, accountId, haEnabled); this.userData = userData; this.displayName = displayName != null ? displayName : null; + this.sshPublicKey = sshPublicKey; } public UserVmVO(long id, @@ -219,24 +198,6 @@ public class UserVmVO extends VMInstanceVO implements UserVm { this.displayName = displayName; } - public UserVmVO(long id, - String instanceName, - String displayName, - long templateId, - long guestOsId, - boolean haEnabled, - long domainId, - long accountId, - long serviceOfferingId, - String userData, - String name, - Long sshKeyPairId, - String sshPublicKey) { - this(id, instanceName, displayName, templateId, guestOsId, haEnabled, domainId, accountId, serviceOfferingId, userData, name); - this.sshKeyPairId = sshKeyPairId; - this.sshPublicKey = sshPublicKey; - } - protected UserVmVO() { super(); } diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index be8cd7b5db5..7d79725d1c1 100644 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -130,6 +130,7 @@ import com.cloud.vm.dao.InstanceGroupVMMapDaoImpl; import com.cloud.vm.dao.NicDaoImpl; import com.cloud.vm.dao.SecondaryStorageVmDaoImpl; import com.cloud.vm.dao.UserVmDaoImpl; +import com.cloud.vm.dao.UserVmDetailsDaoImpl; import com.cloud.vm.dao.VMInstanceDaoImpl; public class DefaultComponentLibrary implements ComponentLibrary { @@ -238,6 +239,8 @@ public class DefaultComponentLibrary implements ComponentLibrary { addDao("SSHKeyPairDao", SSHKeyPairDaoImpl.class); addDao("UsageEventDao", UsageEventDaoImpl.class); addDao("ClusterDetailsDao", ClusterDetailsDaoImpl.class); + addDao("UserVmDetailsDao", UserVmDetailsDaoImpl.class); + } Map> _managers = new HashMap>(); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 8d71bc64264..32d6e24e541 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -262,6 +262,7 @@ import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.InstanceGroupVO; import com.cloud.vm.SecondaryStorageVmVO; +import com.cloud.vm.UserVmDetailVO; import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; @@ -272,6 +273,7 @@ import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.SecondaryStorageVmDao; import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; public class ManagementServerImpl implements ManagementServer { @@ -330,6 +332,7 @@ public class ManagementServerImpl implements ManagementServer { private final UploadDao _uploadDao; private final CertificateDao _certDao; private final SSHKeyPairDao _sshKeyPairDao; + private final UserVmDetailsDao _userVmDetailsDao; private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker")); @@ -403,6 +406,7 @@ public class ManagementServerImpl implements ManagementServer { _tmpltMgr = locator.getManager(TemplateManager.class); _uploadMonitor = locator.getManager(UploadMonitor.class); _sshKeyPairDao = locator.getDao(SSHKeyPairDao.class); + _userVmDetailsDao = locator.getDao(UserVmDetailsDao.class); _userAuthenticators = locator.getAdapters(UserAuthenticator.class); if (_userAuthenticators == null || !_userAuthenticators.isSet()) { @@ -4750,13 +4754,15 @@ public class ManagementServerImpl implements ManagementServer { } @Override - public String getVMPassword(GetVMPasswordCmd cmd) { + public String getVMPassword(GetVMPasswordCmd cmd) { Account account = UserContext.current().getCaller(); UserVmVO vm = _userVmDao.findById(cmd.getId()); - if (vm == null || vm.getEncryptedPassword() == null || vm.getEncryptedPassword().equals("") || vm.getAccountId() != account.getAccountId()) - throw new InvalidParameterValueException("No password for VM with id '" + getId() + "' found."); + UserVmDetailVO password = _userVmDetailsDao.findDetail(cmd.getId(), "Encrypted.Password"); + + if (vm == null || password == null || password.getValue() == null || password.getValue().equals("") || vm.getAccountId() != account.getAccountId()) + throw new InvalidParameterValueException("No password for VM with id '" + getId() + "' found."); - return vm.getEncryptedPassword(); + return password.getValue(); } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 8028efe8f4b..b58a2e1e0c7 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -207,6 +207,7 @@ import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.InstanceGroupVMMapDao; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.UserVmDetailsDao; @Local(value={UserVmManager.class, UserVmService.class}) public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager { private static final Logger s_logger = Logger.getLogger(UserVmManagerImpl.class); @@ -264,6 +265,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager @Inject LoadBalancingRulesManager _lbMgr; @Inject UsageEventDao _usageEventDao; @Inject SSHKeyPairDao _sshKeyPairDao; + @Inject UserVmDetailsDao _vmDetailsDao; private IpAddrAllocator _IpAllocator; ScheduledExecutorService _executor = null; @@ -2237,7 +2239,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } // Find an SSH public key corresponding to the key pair name, if one is given - Long sshKeyPairId = null; String sshPublicKey = null; if (cmd.getSSHKeyPairName() != null && !cmd.getSSHKeyPairName().equals("")) { Account account = UserContext.current().getCaller(); @@ -2245,7 +2246,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager if (pair == null) throw new InvalidParameterValueException("A key pair with name '" + cmd.getSSHKeyPairName() + "' was not found."); - sshKeyPairId = pair.getId(); sshPublicKey = pair.getPublicKey(); } @@ -2306,7 +2306,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager UserVmVO vm = new UserVmVO(id, instanceName, cmd.getDisplayName(), template.getId(), template.getGuestOSId(), offering.getOfferHA(), domainId, owner.getId(), offering.getId(), - userData, hostName, sshKeyPairId, sshPublicKey); + userData, hostName, sshPublicKey); if (_itMgr.allocate(vm, template, offering, rootDiskOffering, dataDiskOfferings, networks, null, plan, cmd.getHypervisor(), owner) == null) { @@ -2340,6 +2340,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { long vmId = cmd.getEntityId(); UserVmVO vm = _vmDao.findById(vmId); + Map vmDetails = _vmDetailsDao.findDetails(vm.getId()); // Check that the password was passed in and is valid VMTemplateVO template = _templateDao.findById(vm.getTemplateId()); @@ -2355,13 +2356,13 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager vm.setPassword(password); // Check if an SSH key pair was selected for the instance and if so use it to encrypt & save the vm password - if (vm.getSSHKeyPairId() != null && vm.getSSHPublicKey() != null && password != null && !password.equals("saved_password") ) { + if (vm.getSSHPublicKey() != null && password != null && !password.equals("saved_password") ) { String encryptedPasswd = RSAHelper.encryptWithSSHPublicKey(vm.getSSHPublicKey(), password); if (encryptedPasswd == null) throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Error encrypting password"); - vm.setEncryptedPassword(encryptedPasswd); - _vmDao.update(vm.getId(), vm); + vmDetails.put("Encrypted.Password", encryptedPasswd); + _vmDetailsDao.persist(vm.getId(), vmDetails); } long userId = UserContext.current().getCallerUserId(); diff --git a/server/src/com/cloud/vm/dao/UserVmDetailsDao.java b/server/src/com/cloud/vm/dao/UserVmDetailsDao.java new file mode 100644 index 00000000000..f3bbd9e51a6 --- /dev/null +++ b/server/src/com/cloud/vm/dao/UserVmDetailsDao.java @@ -0,0 +1,16 @@ +package com.cloud.vm.dao; + +import java.util.Map; + +import com.cloud.utils.db.GenericDao; +import com.cloud.vm.UserVmDetailVO; + +public interface UserVmDetailsDao extends GenericDao { + Map findDetails(long vmId); + + void persist(long vmId, Map details); + + UserVmDetailVO findDetail(long vmId, String name); + + void deleteDetails(long vmId); +} diff --git a/server/src/com/cloud/vm/dao/UserVmDetailsDaoImpl.java b/server/src/com/cloud/vm/dao/UserVmDetailsDaoImpl.java new file mode 100644 index 00000000000..d9ff2b1a4b3 --- /dev/null +++ b/server/src/com/cloud/vm/dao/UserVmDetailsDaoImpl.java @@ -0,0 +1,80 @@ +package com.cloud.vm.dao; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.vm.UserVmDetailVO; + +@Local(value=UserVmDetailsDao.class) +public class UserVmDetailsDaoImpl extends GenericDaoBase implements UserVmDetailsDao { + protected final SearchBuilder VmSearch; + protected final SearchBuilder DetailSearch; + + protected UserVmDetailsDaoImpl() { + VmSearch = createSearchBuilder(); + VmSearch.and("vmId", VmSearch.entity().getVmId(), SearchCriteria.Op.EQ); + VmSearch.done(); + + DetailSearch = createSearchBuilder(); + DetailSearch.and("hostId", DetailSearch.entity().getVmId(), SearchCriteria.Op.EQ); + DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); + DetailSearch.done(); + } + + @Override + public void deleteDetails(long vmId) { + SearchCriteria sc = VmSearch.create(); + sc.setParameters("vmId", vmId); + + List results = search(sc, null); + for (UserVmDetailVO result : results) { + remove(result.getId()); + } + } + + @Override + public UserVmDetailVO findDetail(long vmId, String name) { + SearchCriteria sc = DetailSearch.create(); + sc.setParameters("vmId", vmId); + sc.setParameters("name", name); + + return findOneBy(sc); + } + + @Override + public Map findDetails(long vmId) { + SearchCriteria sc = VmSearch.create(); + sc.setParameters("vmId", vmId); + + List results = search(sc, null); + Map details = new HashMap(results.size()); + for (UserVmDetailVO result : results) { + details.put(result.getName(), result.getValue()); + } + + return details; + } + + @Override + public void persist(long vmId, Map details) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + SearchCriteria sc = VmSearch.create(); + sc.setParameters("vmId", vmId); + expunge(sc); + + for (Map.Entry detail : details.entrySet()) { + UserVmDetailVO vo = new UserVmDetailVO(vmId, detail.getKey(), detail.getValue()); + persist(vo); + } + txn.commit(); + } + +} diff --git a/setup/db/create-index-fk.sql b/setup/db/create-index-fk.sql index 033ec9f2343..998ea1ecd0b 100755 --- a/setup/db/create-index-fk.sql +++ b/setup/db/create-index-fk.sql @@ -123,6 +123,8 @@ ALTER TABLE `cloud`.`user_vm` ADD INDEX `i_user_vm__external_ip_address`(`extern ALTER TABLE `cloud`.`user_vm` ADD CONSTRAINT `fk_user_vm__external_vlan_db_id` FOREIGN KEY `fk_user_vm__external_vlan_db_id` (`external_vlan_db_id`) REFERENCES `vlan` (`id`); ALTER TABLE `cloud`.`user_vm` ADD INDEX `i_user_vm__external_vlan_db_id`(`external_vlan_db_id`); +ALTER TABLE `cloud`.`user_vm_details` ADD CONSTRAINT `fk_user_vm_details__vm_id` FOREIGN KEY `fk_user_vm_details__vm_id`(`vm_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE; + #ALTER TABLE `cloud`.`domain_router` ADD CONSTRAINT `fk_domain_router__public_ip_address` FOREIGN KEY `fk_domain_router__public_ip_address` (`public_ip_address`) REFERENCES `user_ip_address` (`public_ip_address`); ALTER TABLE `cloud`.`domain_router` ADD INDEX `i_domain_router__public_ip_address`(`public_ip_address`); ALTER TABLE `cloud`.`domain_router` ADD CONSTRAINT `fk_domain_router__id` FOREIGN KEY `fk_domain_router__id` (`id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE; diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 1d5436969b2..9fc06341d9a 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -760,12 +760,19 @@ CREATE TABLE `cloud`.`user_vm` ( `external_mac_address` varchar(17) COMMENT 'mac address within the external network', `external_vlan_db_id` bigint unsigned COMMENT 'foreign key into vlan table', `user_data` varchar(2048), - `encrypted_password` varchar(1024) COMMENT 'vm password encrypted with the public key referenced in ssh_keypair', - `ssh_keypair_id` bigint unsigned COMMENT 'id of the ssh keypair used to access the vm and/or encrypt the password', `ssh_public_key` varchar(5120) COMMENT 'ssh public key', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `cloud`.`user_vm_details` ( + `id` bigint unsigned NOT NULL auto_increment, + `vm_id` bigint unsigned NOT NULL COMMENT 'vm id', + `name` varchar(255) NOT NULL, + `value` varchar(1024) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + CREATE TABLE `cloud`.`domain_router` ( `id` bigint unsigned UNIQUE NOT NULL COMMENT 'Primary Key', `gateway` varchar(15) COMMENT 'ip address of the gateway to this domR',