diff --git a/api/src/com/cloud/acl/SecurityChecker.java b/api/src/com/cloud/acl/SecurityChecker.java index b878ca0b005..d39e9841c2a 100644 --- a/api/src/com/cloud/acl/SecurityChecker.java +++ b/api/src/com/cloud/acl/SecurityChecker.java @@ -3,12 +3,9 @@ */ package com.cloud.acl; -import java.security.acl.NotOwnerException; - -import com.cloud.domain.PartOf; +import com.cloud.domain.Domain; import com.cloud.exception.PermissionDeniedException; import com.cloud.user.Account; -import com.cloud.user.OwnedBy; import com.cloud.user.User; import com.cloud.utils.component.Adapter; @@ -25,7 +22,7 @@ public interface SecurityChecker extends Adapter { * @return true if access allowed. false if this adapter cannot authenticate ownership. * @throws PermissionDeniedException if this adapter is suppose to authenticate ownership and the check failed. */ - boolean checkOwnership(Account account, OwnedBy object) throws NotOwnerException; + boolean checkAccess(Account account, Domain domain) throws PermissionDeniedException; /** * Checks if the user belongs to an account that owns the object. @@ -35,27 +32,27 @@ public interface SecurityChecker extends Adapter { * @return true if access allowed. false if this adapter cannot authenticate ownership. * @throws PermissionDeniedException if this adapter is suppose to authenticate ownership and the check failed. */ - boolean checkOwnership(User user, OwnedBy object) throws NotOwnerException; + boolean checkAccess(User user, Domain domain) throws PermissionDeniedException; /** * Checks if the account can access the object. * * @param account account to check against. - * @param object object that the account is trying to access. + * @param entity object that the account is trying to access. * @return true if access allowed. false if this adapter cannot provide permission. * @throws PermissionDeniedException if this adapter is suppose to authenticate ownership and the check failed. */ - boolean checkAccess(Account account, PartOf object) throws PermissionDeniedException; + boolean checkAccess(Account account, ControlledEntity entity) throws PermissionDeniedException; /** * Checks if the user belongs to an account that can access the object. * * @param user user to check against. - * @param object object that the account is trying to access. + * @param entity object that the account is trying to access. * @return true if access allowed. false if this adapter cannot authenticate ownership. * @throws PermissionDeniedException if this adapter is suppose to authenticate ownership and the check failed. */ - boolean checkAccess(User user, PartOf object) throws PermissionDeniedException; + boolean checkAccess(User user, ControlledEntity entity) throws PermissionDeniedException; // We should be able to use this method to check against commands. For example, we can // annotate the command with access annotations and this method can use it to extract diff --git a/api/src/com/cloud/network/NetworkConfiguration.java b/api/src/com/cloud/network/NetworkConfiguration.java index bed8dcae9ea..25d125bc878 100644 --- a/api/src/com/cloud/network/NetworkConfiguration.java +++ b/api/src/com/cloud/network/NetworkConfiguration.java @@ -92,4 +92,8 @@ public interface NetworkConfiguration extends OwnedBy, PartOf { State getState(); long getRelated(); + + String getBroadcastUri(); + + String getDns(); } diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java index bd663f142f6..dbcf926b93e 100755 --- a/api/src/com/cloud/storage/Volume.java +++ b/api/src/com/cloud/storage/Volume.java @@ -21,14 +21,13 @@ import java.util.Date; import java.util.List; import java.util.Set; -import com.cloud.domain.PartOf; +import com.cloud.acl.ControlledEntity; import com.cloud.template.BasedOn; -import com.cloud.user.OwnedBy; import com.cloud.utils.fsm.FiniteState; import com.cloud.utils.fsm.StateMachine; -public interface Volume extends PartOf, OwnedBy, BasedOn { +public interface Volume extends ControlledEntity, BasedOn { enum VolumeType {UNKNOWN, ROOT, SWAP, DATADISK, ISO}; enum MirrorState {NOT_MIRRORED, ACTIVE, DEFUNCT}; diff --git a/api/src/com/cloud/template/VirtualMachineTemplate.java b/api/src/com/cloud/template/VirtualMachineTemplate.java index 1697c1f5a3b..d740db19d0a 100755 --- a/api/src/com/cloud/template/VirtualMachineTemplate.java +++ b/api/src/com/cloud/template/VirtualMachineTemplate.java @@ -17,9 +17,9 @@ */ package com.cloud.template; -import com.cloud.storage.Storage.FileSystem; +import com.cloud.acl.ControlledEntity; -public interface VirtualMachineTemplate { +public interface VirtualMachineTemplate extends ControlledEntity { public static enum BootloaderType { PyGrub, HVM, External, CD }; diff --git a/api/src/com/cloud/user/Account.java b/api/src/com/cloud/user/Account.java index d8cc9f84d4e..557bb876fb6 100644 --- a/api/src/com/cloud/user/Account.java +++ b/api/src/com/cloud/user/Account.java @@ -53,8 +53,10 @@ public interface Account extends PartOf { public short getType(); public String getState(); public void setState(String state); + @Override public long getDomainId(); public Date getRemoved(); public String getNetworkDomain(); public void setNetworkDomain(String networkDomain); + } diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index 1984f83eac6..70b6eab45a9 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -19,14 +19,13 @@ package com.cloud.vm; import java.util.Date; -import com.cloud.domain.PartOf; -import com.cloud.user.OwnedBy; +import com.cloud.acl.ControlledEntity; /** * VirtualMachine describes the properties held by a virtual machine * */ -public interface VirtualMachine extends RunningOn, OwnedBy, PartOf { +public interface VirtualMachine extends RunningOn, ControlledEntity { public enum Event { CreateRequested, StartRequested, diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index e1989cbc6a3..f6f76565f72 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -33,7 +33,7 @@ updateResourceLimit=com.cloud.api.commands.UpdateResourceLimitCmd;3 listResourceLimits=com.cloud.api.commands.ListResourceLimitsCmd;15 #### VM commands -deployVirtualMachine=com.cloud.api.commands.DeployVMCmd;11 +deployVirtualMachine=com.cloud.api.commands.DeployVm2Cmd;11 destroyVirtualMachine=com.cloud.api.commands.DestroyVMCmd;15 rebootVirtualMachine=com.cloud.api.commands.RebootVMCmd;15 startVirtualMachine=com.cloud.api.commands.StartVMCmd;15 diff --git a/core/src/com/cloud/domain/DomainVO.java b/core/src/com/cloud/domain/DomainVO.java index 9b97065723c..90ebd1e10a3 100644 --- a/core/src/com/cloud/domain/DomainVO.java +++ b/core/src/com/cloud/domain/DomainVO.java @@ -71,14 +71,17 @@ public class DomainVO implements Domain { this.level = 0; } + @Override public long getId() { return id; } + @Override public Long getParent() { return parent; } + @Override public void setParent(Long parent) { if(parent == null) { this.parent = DomainVO.ROOT_DOMAIN; @@ -90,30 +93,37 @@ public class DomainVO implements Domain { } } + @Override public String getName() { return name; } + @Override public void setName(String name) { this.name = name; } + @Override public long getAccountId() { return accountId; } + @Override public Date getRemoved() { return removed; } + @Override public String getPath() { return path; } + @Override public void setPath(String path) { this.path = path; } + @Override public int getLevel() { return level; } @@ -122,6 +132,7 @@ public class DomainVO implements Domain { this.level = level; } + @Override public int getChildCount() { return childCount; } @@ -130,12 +141,18 @@ public class DomainVO implements Domain { childCount = count; } + @Override public long getNextChildSeq() { return nextChildSeq; } public void setNextChildSeq(long seq) { nextChildSeq = seq; + } + + @Override + public String toString() { + return new StringBuilder("Domain:").append(id).append(path).toString(); } } diff --git a/core/src/com/cloud/offerings/NetworkOfferingVO.java b/core/src/com/cloud/offerings/NetworkOfferingVO.java index 6a0a4339501..e4a034c3a80 100644 --- a/core/src/com/cloud/offerings/NetworkOfferingVO.java +++ b/core/src/com/cloud/offerings/NetworkOfferingVO.java @@ -30,6 +30,7 @@ import javax.persistence.Table; import com.cloud.network.Network.TrafficType; import com.cloud.offering.NetworkOffering; +import com.cloud.service.ServiceOfferingVO; import com.cloud.utils.db.GenericDao; @Entity @@ -72,6 +73,9 @@ public class NetworkOfferingVO implements NetworkOffering { @Column(name="system_only") boolean systemOnly; + @Column(name="service_offering_id") + Long serviceOfferingId; + @Column(name="tags") String tags; @@ -128,6 +132,14 @@ public class NetworkOfferingVO implements NetworkOffering { return removed; } + public Long getServiceOfferingId() { + return serviceOfferingId; + } + + public void setServiceOfferingId(long serviceOfferingId) { + this.serviceOfferingId = serviceOfferingId; + } + @Override public Integer getConcurrentConnections() { return concurrentConnections; @@ -144,6 +156,50 @@ public class NetworkOfferingVO implements NetworkOffering { public NetworkOfferingVO() { } + public void setName(String name) { + this.name = name; + } + + public void setDisplayText(String displayText) { + this.displayText = displayText; + } + + public void setRateMbps(Integer rateMbps) { + this.rateMbps = rateMbps; + } + + public void setMulticastRateMbps(Integer multicastRateMbps) { + this.multicastRateMbps = multicastRateMbps; + } + + public void setConcurrentConnections(Integer concurrentConnections) { + this.concurrentConnections = concurrentConnections; + } + + public void setGuestIpType(GuestIpType guestIpType) { + this.guestIpType = guestIpType; + } + + public void setTrafficType(TrafficType trafficType) { + this.trafficType = trafficType; + } + + public void setSystemOnly(boolean systemOnly) { + this.systemOnly = systemOnly; + } + + public void setServiceOfferingId(Long serviceOfferingId) { + this.serviceOfferingId = serviceOfferingId; + } + + public void setRemoved(Date removed) { + this.removed = removed; + } + + public void setCreated(Date created) { + this.created = created; + } + public NetworkOfferingVO(String name, String displayText, TrafficType trafficType, GuestIpType type, boolean systemOnly, Integer rateMbps, Integer multicastRateMbps, Integer concurrentConnections) { this.name = name; this.displayText = displayText; @@ -155,6 +211,11 @@ public class NetworkOfferingVO implements NetworkOffering { this.systemOnly = systemOnly; } + public NetworkOfferingVO(ServiceOfferingVO offering) { + this("Network Offering for " + offering.getName(), "Network Offering for " + offering.getDisplayText(), TrafficType.Guest, offering.getGuestIpType(), false, offering.getRateMbps(), offering.getMulticastRateMbps(), null); + this.serviceOfferingId = offering.getId(); + } + /** * Network Offering for all system vms. * @param name diff --git a/core/src/com/cloud/storage/VMTemplateVO.java b/core/src/com/cloud/storage/VMTemplateVO.java index f21e28a1b85..87ee98bc1e3 100644 --- a/core/src/com/cloud/storage/VMTemplateVO.java +++ b/core/src/com/cloud/storage/VMTemplateVO.java @@ -18,28 +18,23 @@ package com.cloud.storage; -import java.util.Date; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.TableGenerator; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; - -import com.cloud.async.AsyncInstanceCreateStatus; +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.TableGenerator; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; + import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.storage.Storage.FileSystem; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; -import com.cloud.utils.db.GenericDao; -import com.google.gson.annotations.Expose; -import com.cloud.storage.Storage; import com.cloud.template.VirtualMachineTemplate; +import com.cloud.utils.db.GenericDao; @Entity @Table(name="vm_template") @@ -248,7 +243,8 @@ public class VMTemplateVO implements VirtualMachineTemplate { requiresHvm = value; } - public long getAccountId() { + @Override + public long getAccountId() { return accountId; } @@ -303,6 +299,11 @@ public class VMTemplateVO implements VirtualMachineTemplate { public void setHypervisorType(HypervisorType hyperType) { hypervisorType = hyperType.toString(); } + + @Override + public long getDomainId() { + return -1; + } @Override public boolean equals(Object that) { @@ -320,5 +321,15 @@ public class VMTemplateVO implements VirtualMachineTemplate { public int hashCode() { return uniqueName.hashCode(); } + + @Transient + String toString; + @Override + public String toString() { + if (toString == null) { + toString = new StringBuilder("Template:").append(id).append(":").append(format).append(":").append(uniqueName).toString(); + } + return toString; + } } diff --git a/core/src/com/cloud/user/AccountVO.java b/core/src/com/cloud/user/AccountVO.java index d47d7ddbbb5..bccb54a2749 100644 --- a/core/src/com/cloud/user/AccountVO.java +++ b/core/src/com/cloud/user/AccountVO.java @@ -77,12 +77,15 @@ public class AccountVO implements Account { return id; } + @Override public String getAccountName() { return accountName; } + @Override public void setAccountName(String accountName) { this.accountName = accountName; } + @Override public short getType() { return type; } @@ -90,6 +93,7 @@ public class AccountVO implements Account { this.type = type; } + @Override public long getDomainId() { return domainId; } @@ -98,20 +102,30 @@ public class AccountVO implements Account { this.domainId = domainId; } + @Override public String getState() { return state; } + @Override public void setState(String state) { this.state = state; } + @Override public Date getRemoved() { return removed; } + @Override public String getNetworkDomain() { return networkDomain; } + @Override public void setNetworkDomain(String networkDomain) { this.networkDomain = networkDomain; + } + + @Override + public String toString() { + return new StringBuilder("Acct:").append(id).append(":").append(accountName).toString(); } } diff --git a/core/src/com/cloud/user/UserVO.java b/core/src/com/cloud/user/UserVO.java index 2c04e9f48d4..6138a58ffea 100644 --- a/core/src/com/cloud/user/UserVO.java +++ b/core/src/com/cloud/user/UserVO.java @@ -18,15 +18,16 @@ package com.cloud.user; -import java.util.Date; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; - +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; + import com.cloud.utils.db.GenericDao; /** @@ -84,77 +85,111 @@ public class UserVO implements User { this.id = id; } - public Long getId() { + @Override + public Long getId() { return id; } + @Override public Date getCreated() { return created; } + @Override public Date getRemoved() { return removed; } - public String getUsername() { + @Override + public String getUsername() { return username; } - public void setUsername(String username) { + @Override + public void setUsername(String username) { this.username = username; } - public String getPassword() { + @Override + public String getPassword() { return password; } - public void setPassword(String password) { + @Override + public void setPassword(String password) { this.password = password; } - public String getFirstname() { + @Override + public String getFirstname() { return firstname; } - public void setFirstname(String firstname) { + @Override + public void setFirstname(String firstname) { this.firstname = firstname; } - public String getLastname() { + @Override + public String getLastname() { return lastname; } - public void setLastname(String lastname) { + @Override + public void setLastname(String lastname) { this.lastname = lastname; } - public long getAccountId() { + @Override + public long getAccountId() { return accountId; } - public void setAccountId(long accountId) { + @Override + public void setAccountId(long accountId) { this.accountId = accountId; } + @Override public String getEmail() { return email; } + @Override public void setEmail(String email) { this.email = email; } + @Override public String getState() { return state; } + @Override public void setState(String state) { this.state = state; } - public String getApiKey() { + @Override + public String getApiKey() { return apiKey; } - public void setApiKey(String apiKey) { + @Override + public void setApiKey(String apiKey) { this.apiKey = apiKey; } + @Override public String getSecretKey() { return secretKey; } + @Override public void setSecretKey(String secretKey) { this.secretKey = secretKey; } + @Override public String getTimezone() { return timezone; } + @Override public void setTimezone(String timezone) { this.timezone = timezone; + } + + @Transient + String toString = null; + + @Override + public String toString() { + if (toString == null) { + toString = new StringBuilder("User:").append(id).append(":").append(username).toString(); + } + return toString; } } diff --git a/core/src/com/cloud/vm/UserVmVO.java b/core/src/com/cloud/vm/UserVmVO.java index b4c9049fa94..18716657636 100755 --- a/core/src/com/cloud/vm/UserVmVO.java +++ b/core/src/com/cloud/vm/UserVmVO.java @@ -139,7 +139,6 @@ public class UserVmVO extends VMInstanceVO implements UserVm { super(id, serviceOfferingId, displayName, instanceName, Type.User, templateId, guestOsId, domainId, accountId, haEnabled); this.userData = userData; this.displayName = displayName; - } public UserVmVO(long id, diff --git a/server/src/com/cloud/api/commands/DeployVm2Cmd.java b/server/src/com/cloud/api/commands/DeployVm2Cmd.java index 8ad461b8ba2..5ec94a8d779 100644 --- a/server/src/com/cloud/api/commands/DeployVm2Cmd.java +++ b/server/src/com/cloud/api/commands/DeployVm2Cmd.java @@ -23,8 +23,9 @@ import java.util.List; import org.apache.log4j.Logger; import com.cloud.api.ApiDBUtils; -import com.cloud.api.BaseAsyncCmd; +import com.cloud.api.BaseAsyncCreateCmd; import com.cloud.api.BaseCmd; +import com.cloud.api.BaseCmd.CommandType; import com.cloud.api.BaseCmd.Manager; import com.cloud.api.Implementation; import com.cloud.api.Parameter; @@ -39,7 +40,7 @@ import com.cloud.uservm.UserVm; import com.cloud.vm.InstanceGroupVO; @Implementation(createMethod="createVirtualMachine", method="startVirtualMachine", manager=Manager.UserVmManager, description="Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.") -public class DeployVm2Cmd extends BaseAsyncCmd { +public class DeployVm2Cmd extends BaseAsyncCreateCmd { public static final Logger s_logger = Logger.getLogger(DeployVMCmd.class.getName()); private static final String s_name = "deployvirtualmachineresponse"; diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 6bc8aaf3e49..875d7fe483f 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -2429,7 +2429,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach } @Override - public boolean checkDeploymentResult(Commands cmds, ConsoleProxyVO proxy, VirtualMachineProfile profile, DeployDestination dest) { + public boolean processDeploymentResult(Commands cmds, ConsoleProxyVO proxy, VirtualMachineProfile profile, DeployDestination dest) { return true; } } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 1f0823a3a13..24fb515a524 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -316,4 +316,6 @@ public interface NetworkManager extends Manager { AccountVO getNetworkConfigurationOwner(long configurationId); List getNetworkConfigurationsforOffering(long offeringId, long dataCenterId, long accountId); + + List setupNetworkConfiguration(Account owner, ServiceOfferingVO offering, DeploymentPlan plan); } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index ab8f755254d..90c27bc4331 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1789,16 +1789,47 @@ public class NetworkManagerImpl implements NetworkManager, DomainRouterService { return to; } + @DB + protected Pair implementNetworkConfiguration(long configId, DeployDestination dest) throws ConcurrentOperationException { + Transaction txn = Transaction.currentTxn(); + NetworkConfigurationVO config = _networkConfigDao.acquire(configId); + if (config == null) { + throw new ConcurrentOperationException("Unable to acquire network configuration: " + configId); + } + + try { + NetworkGuru guru = _networkGurus.get(config.getGuruName()); + if (config.getState() == NetworkConfiguration.State.Implemented || config.getState() == NetworkConfiguration.State.Setup) { + return new Pair(guru, config); + } + + + NetworkConfiguration result = guru.implement(config, _networkOfferingDao.findById(config.getNetworkOfferingId()), dest); + config.setCidr(result.getCidr()); + config.setBroadcastUri(result.getBroadcastUri()); + config.setGateway(result.getGateway()); + config.setDns(result.getDns()); + config.setMode(result.getMode()); + config.setState(NetworkConfiguration.State.Implemented); + _networkConfigDao.update(configId, config); + + return new Pair(guru, config); + } finally { + _networkConfigDao.release(configId); + } + } + @Override public NicTO[] prepare(VirtualMachineProfile vmProfile, DeployDestination dest, Account user) throws InsufficientAddressCapacityException, InsufficientVirtualNetworkCapcityException, ConcurrentOperationException, ResourceUnavailableException { List nics = _nicDao.listBy(vmProfile.getId()); NicTO[] nicTos = new NicTO[nics.size()]; int i = 0; for (NicVO nic : nics) { - NetworkConfigurationVO config = _networkConfigDao.findById(nic.getNetworkConfigurationId()); + Pair implemented = implementNetworkConfiguration(nic.getNetworkConfigurationId(), dest); + NetworkGuru concierge = implemented.first(); + NetworkConfigurationVO config = implemented.second(); NicProfile profile = null; if (nic.getReservationStrategy() == ReservationStrategy.Start) { - NetworkGuru concierge = _networkGurus.get(config.getGuruName()); nic.setState(Resource.State.Reserving); _nicDao.update(nic.getId(), nic); profile = toNicProfile(nic); @@ -2490,4 +2521,11 @@ public class NetworkManagerImpl implements NetworkManager, DomainRouterService { public List getNetworkConfigurationsforOffering(long offeringId, long dataCenterId, long accountId) { return _networkConfigDao.getNetworkConfigurationsForOffering(offeringId, dataCenterId, accountId); } + + @Override + public List setupNetworkConfiguration(Account owner, ServiceOfferingVO offering, DeploymentPlan plan) { + NetworkOfferingVO networkOffering = _networkOfferingDao.findByServiceOffering(offering); + return setupNetworkConfiguration(owner, networkOffering, plan); + } + } diff --git a/server/src/com/cloud/network/router/DomainRouterManagerImpl.java b/server/src/com/cloud/network/router/DomainRouterManagerImpl.java index ff037fd9db1..dff4271b733 100644 --- a/server/src/com/cloud/network/router/DomainRouterManagerImpl.java +++ b/server/src/com/cloud/network/router/DomainRouterManagerImpl.java @@ -1999,12 +1999,11 @@ public class DomainRouterManagerImpl implements DomainRouterManager, VirtualMach @Override @DB public DomainRouterVO deploy(NetworkConfiguration publicConfig, NetworkConfiguration virtualConfig, NetworkOffering offering, Account owner) throws InsufficientCapacityException, StorageUnavailableException, ConcurrentOperationException, ResourceUnavailableException { - long dcId = publicConfig.getDataCenterId(); + long dcId = virtualConfig.getDataCenterId(); if (s_logger.isDebugEnabled()) { s_logger.debug("Starting a router for network configurations: public=" + publicConfig + "; virtual=" + virtualConfig); } - assert dcId == virtualConfig.getDataCenterId() : "Domain router cannot span networks in two data centers"; assert publicConfig.getState() == NetworkConfiguration.State.Implemented : "Network is not yet fully implemented: " + publicConfig; assert virtualConfig.getState() == NetworkConfiguration.State.Implemented : "Network is not yet fully implemented: " + virtualConfig; @@ -2092,7 +2091,7 @@ public class DomainRouterManagerImpl implements DomainRouterManager, VirtualMach } @Override - public boolean checkDeploymentResult(Commands cmds, DomainRouterVO router, VirtualMachineProfile profile, DeployDestination dest) { + public boolean processDeploymentResult(Commands cmds, DomainRouterVO router, VirtualMachineProfile profile, DeployDestination dest) { return true; } diff --git a/server/src/com/cloud/offerings/dao/NetworkOfferingDao.java b/server/src/com/cloud/offerings/dao/NetworkOfferingDao.java index f244864c97c..60e478f37ca 100644 --- a/server/src/com/cloud/offerings/dao/NetworkOfferingDao.java +++ b/server/src/com/cloud/offerings/dao/NetworkOfferingDao.java @@ -4,6 +4,7 @@ package com.cloud.offerings.dao; import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.service.ServiceOfferingVO; import com.cloud.utils.db.GenericDao; /** @@ -28,4 +29,6 @@ public interface NetworkOfferingDao extends GenericDao * @return NetworkOfferingVO backed by a row in the database */ NetworkOfferingVO persistSystemNetworkOffering(NetworkOfferingVO offering); + + NetworkOfferingVO findByServiceOffering(ServiceOfferingVO offering); } diff --git a/server/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java b/server/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java index dc63e8dd0a8..08c7dc4ca68 100644 --- a/server/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java +++ b/server/src/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java @@ -3,17 +3,27 @@ */ package com.cloud.offerings.dao; + import javax.ejb.Local; import javax.persistence.EntityExistsException; +import org.apache.log4j.Logger; + import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.exception.CloudRuntimeException; -@Local(value=NetworkOfferingDao.class) +@Local(value=NetworkOfferingDao.class) @DB(txn=false) public class NetworkOfferingDaoImpl extends GenericDaoBase implements NetworkOfferingDao { - SearchBuilder NameSearch; + + private final static Logger s_logger = Logger.getLogger(NetworkOfferingDaoImpl.class); + + SearchBuilder NameSearch; + SearchBuilder ServiceOfferingSearch; protected NetworkOfferingDaoImpl() { super(); @@ -21,6 +31,10 @@ public class NetworkOfferingDaoImpl extends GenericDaoBase sc = ServiceOfferingSearch.create(); + sc.setParameters("serviceoffering", offering.getId()); + + NetworkOfferingVO vo = findOneBy(sc); + if (vo != null) { + return vo; + } + + vo = new NetworkOfferingVO(offering); + try { + return persist(vo); + } catch (Exception e) { + s_logger.debug("Got a persistence exception. Assuming it's because service offering id is duplicate"); + vo = findOneBy(sc); + if (vo != null) { + return vo; + } + + throw new CloudRuntimeException("Unable to persist network offering", e); + } + } } diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java index 210f1ebdca7..f43de56fdb9 100644 --- a/server/src/com/cloud/user/AccountManager.java +++ b/server/src/com/cloud/user/AccountManager.java @@ -20,11 +20,13 @@ package com.cloud.user; import java.util.List; +import com.cloud.acl.ControlledEntity; import com.cloud.api.commands.ListResourceLimitsCmd; import com.cloud.api.commands.UpdateResourceLimitCmd; import com.cloud.configuration.ResourceCount; import com.cloud.configuration.ResourceCount.ResourceType; import com.cloud.configuration.ResourceLimitVO; +import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; @@ -114,5 +116,9 @@ public interface AccountManager extends Manager { */ ResourceLimitVO updateResourceLimit(UpdateResourceLimitCmd cmd) throws InvalidParameterValueException; + void checkAccess(Account account, Domain domain) throws PermissionDeniedException; + + void checkAccess(Account account, ControlledEntity... entities) throws PermissionDeniedException; + AccountVO getSystemAccount(); } diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index b7282e96750..64b7d3f09e1 100644 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -27,6 +27,8 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; +import com.cloud.acl.ControlledEntity; +import com.cloud.acl.SecurityChecker; import com.cloud.api.BaseCmd; import com.cloud.api.ServerApiException; import com.cloud.api.commands.ListResourceLimitsCmd; @@ -35,12 +37,14 @@ import com.cloud.configuration.ResourceCount.ResourceType; import com.cloud.configuration.ResourceLimitVO; import com.cloud.configuration.dao.ResourceCountDao; import com.cloud.configuration.dao.ResourceLimitDao; +import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.server.Criteria; import com.cloud.user.dao.AccountDao; +import com.cloud.utils.component.Adapters; import com.cloud.utils.component.Inject; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GlobalLock; @@ -59,6 +63,8 @@ public class AccountManagerImpl implements AccountManager { private final GlobalLock m_resourceCountLock = GlobalLock.getInternLock("resource.count"); AccountVO _systemAccount; + @Inject(adapter=SecurityChecker.class) + Adapters _securityCheckers; @Override public boolean configure(final String name, final Map params) throws ConfigurationException { @@ -342,7 +348,7 @@ public class AccountManagerImpl implements AccountManager { String accountName = cmd.getAccountName(); Long domainId = cmd.getDomainId(); Long accountId = null; - Account account = (Account)UserContext.current().getAccount(); + Account account = UserContext.current().getAccount(); if ((account == null) || (account.getType() == Account.ACCOUNT_TYPE_ADMIN) || @@ -409,7 +415,7 @@ public class AccountManagerImpl implements AccountManager { @Override public ResourceLimitVO updateResourceLimit(UpdateResourceLimitCmd cmd) throws InvalidParameterValueException { - Account account = (Account)UserContext.current().getAccount(); + Account account = UserContext.current().getAccount(); String accountName = cmd.getAccountName(); Long domainId = cmd.getDomainId(); Long max = cmd.getMax(); @@ -560,4 +566,41 @@ public class AccountManagerImpl implements AccountManager { public AccountVO getSystemAccount() { return _systemAccount; } + + public static boolean isAdmin(short accountType) { + return ((accountType == Account.ACCOUNT_TYPE_ADMIN) || + (accountType == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) || + (accountType == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)); + } + + @Override + public void checkAccess(Account caller, Domain domain) throws PermissionDeniedException { + for (SecurityChecker checker : _securityCheckers) { + if (checker.checkAccess(caller, domain)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Access granted to " + caller + " to " + domain + " by " + checker.getName()); + } + return; + } + } + + assert false : "How can all of the security checkers pass on checking this caller?"; + throw new PermissionDeniedException("There's no way to confirm " + caller + " has access to " + domain); + } + + @Override + public void checkAccess(Account caller, ControlledEntity... entities) { + for (ControlledEntity entity : entities) { + for (SecurityChecker checker : _securityCheckers) { + if (checker.checkAccess(caller, entity)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Access to " + entity + " granted to " + caller + " by " + checker.getName()); + } + } + } + + assert false : "How can all of the security checkers pass on checking this check?"; + throw new PermissionDeniedException("There's no way to confirm " + caller + " has access to " + entity); + } + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 58b888adb6b..81e0819da03 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -106,6 +106,9 @@ import com.cloud.dc.dao.AccountVlanMapDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.VlanDao; +import com.cloud.deploy.DataCenterDeployment; +import com.cloud.deploy.DeployDestination; +import com.cloud.domain.Domain; import com.cloud.domain.dao.DomainDao; import com.cloud.event.EventState; import com.cloud.event.EventTypes; @@ -132,6 +135,7 @@ import com.cloud.network.FirewallRuleVO; import com.cloud.network.IPAddressVO; import com.cloud.network.IpAddrAllocator; import com.cloud.network.LoadBalancerVMMapVO; +import com.cloud.network.NetworkConfigurationVO; import com.cloud.network.NetworkManager; import com.cloud.network.SecurityGroupVMMapVO; import com.cloud.network.dao.FirewallRulesDao; @@ -205,7 +209,7 @@ import com.cloud.vm.dao.InstanceGroupVMMapDao; import com.cloud.vm.dao.UserVmDao; @Local(value={UserVmManager.class, UserVmService.class}) -public class UserVmManagerImpl implements UserVmManager, UserVmService { +public class UserVmManagerImpl implements UserVmManager, UserVmService, VirtualMachineGuru { private static final Logger s_logger = Logger.getLogger(UserVmManagerImpl.class); private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3 seconds @@ -250,12 +254,14 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService { @Inject AccountVlanMapDao _accountVlanMapDao; @Inject StoragePoolDao _storagePoolDao; @Inject VMTemplateHostDao _vmTemplateHostDao; - @Inject NetworkGroupManager _networkGroupManager; + @Inject NetworkGroupManager _networkGroupMgr; @Inject ServiceOfferingDao _serviceOfferingDao; @Inject EventDao _eventDao = null; @Inject InstanceGroupDao _vmGroupDao; @Inject InstanceGroupVMMapDao _groupVMMapDao; - + @Inject SecurityGroupDao _networkSecurityGroupDao; + @Inject VmManager _itMgr; + private IpAddrAllocator _IpAllocator; ScheduledExecutorService _executor = null; int _expungeInterval; @@ -265,6 +271,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService { String _name; String _instance; String _zone; + String _defaultNetworkDomain; Random _rand = new Random(System.currentTimeMillis()); @@ -1112,7 +1119,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService { event.setDescription("successfully started VM: " + vm.getName()); _eventDao.persist(event); - _networkGroupManager.handleVmStateTransition(vm, State.Running); + _networkGroupMgr.handleVmStateTransition(vm, State.Running); return _vmDao.findById(vm.getId()); } catch (Throwable th) { @@ -2174,6 +2181,14 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService { } Map configs = _configDao.getConfiguration("AgentManager", params); + + _defaultNetworkDomain = configs.get("domain"); + if (_defaultNetworkDomain == null) { + _defaultNetworkDomain = ".myvm.com"; + } + if (!_defaultNetworkDomain.startsWith(".")) { + _defaultNetworkDomain = "." + _defaultNetworkDomain; + } String value = configs.get("start.retry"); _retry = NumbersUtil.parseInt(value, 2); @@ -2244,7 +2259,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService { @Override public void completeStartCommand(UserVmVO vm) { _vmDao.updateIf(vm, Event.AgentReportRunning, vm.getHostId()); - _networkGroupManager.handleVmStateTransition(vm, State.Running); + _networkGroupMgr.handleVmStateTransition(vm, State.Running); } @@ -2278,7 +2293,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService { } txn.commit(); - _networkGroupManager.handleVmStateTransition(vm, State.Stopped); + _networkGroupMgr.handleVmStateTransition(vm, State.Stopped); } catch (Throwable th) { s_logger.error("Error during stop: ", th); throw new CloudRuntimeException("Error during stop: ", th); @@ -2508,7 +2523,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService { _storageMgr.destroy(vm, vols); _vmDao.remove(vm.getId()); - _networkGroupManager.removeInstanceFromGroups(vm.getId()); + _networkGroupMgr.removeInstanceFromGroups(vm.getId()); removeInstanceFromGroup(vm.getId()); s_logger.debug("vm is destroyed"); @@ -3133,7 +3148,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService { vm.setLastHostId(pod.second()); vm = _vmDao.persist(vm); - boolean addedToGroups = _networkGroupManager.addInstanceToGroups(vmId, networkGroups); + boolean addedToGroups = _networkGroupMgr.addInstanceToGroups(vmId, networkGroups); if (!addedToGroups) { s_logger.warn("Not all specified network groups can be found"); _vmDao.expunge(vm.getId()); @@ -3298,7 +3313,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService { vm.setLastHostId(pod.second()); _vmDao.persist(vm); - _networkGroupManager.addInstanceToGroups(vmId, networkGroups); + _networkGroupMgr.addInstanceToGroups(vmId, networkGroups); _accountMgr.incrementResourceCount(account.getId(), ResourceType.user_vm); _accountMgr.incrementResourceCount(account.getId(), ResourceType.volume, numVolumes); @@ -3776,193 +3791,174 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService { } } - @Override + private boolean validPassword(String password) { + for (int i = 0; i < password.length(); i++) { + if (password.charAt(i) == ' ') { + return false; + } + } + return true; + } + + @Override @DB public UserVm createVirtualMachine(DeployVm2Cmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException { -// Account account = UserContext.current().getAccount(); -// Account ctxAccount = UserContext.current().getAccount(); -// Long userId = UserContext.current().getUserId(); -// String accountName = cmd.getAccountName(); -// Long domainId = cmd.getDomainId(); -// Long accountId = null; -// long dataCenterId = cmd.getZoneId(); -// long serviceOfferingId = cmd.getServiceOfferingId(); -// long templateId = cmd.getTemplateId(); -// Long diskOfferingId = cmd.getDiskOfferingId(); -// String domain = null; // FIXME: this was hardcoded to null in DeployVMCmd in the old framework, do we need it? -// String password = generateRandomPassword(); -// String displayName = cmd.getDisplayName(); -// String group = cmd.getGroup(); -// String userData = cmd.getUserData(); -// String[] networkGroups = null; -// Long sizeObj = cmd.getSize(); -// long size = (sizeObj == null) ? 0 : sizeObj; -// -// if ((ctxAccount == null) || isAdmin(ctxAccount.getType())) { -// if (domainId != null) { -// if ((ctxAccount != null) && !_domainDao.isChildDomain(ctxAccount.getDomainId(), domainId)) { -// throw new PermissionDeniedException("Failed to deploy VM, invalid domain id (" + domainId + ") given."); -// } -// if (accountName != null) { -// Account userAccount = _accountDao.findActiveAccount(accountName, domainId); -// if (userAccount == null) { -// throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId); -// } -// accountId = userAccount.getId(); -// } -// } else { -// accountId = ((ctxAccount != null) ? ctxAccount.getId() : null); -// } -// } else { -// accountId = ctxAccount.getId(); -// } -// -// if (accountId == null) { -// throw new InvalidParameterValueException("No valid account specified for deploying a virtual machine."); -// } -// -// List netGrpList = cmd.getNetworkGroupList(); -// if ((netGrpList != null) && !netGrpList.isEmpty()) { -// networkGroups = netGrpList.toArray(new String[netGrpList.size()]); -// } -// -// AccountVO account = _accountDao.findById(accountId); -// if (account == null) { -// throw new InvalidParameterValueException("Unable to find account: " + accountId); -// } -// -// DataCenterVO dc = _dcDao.findById(dataCenterId); -// if (dc == null) { -// throw new InvalidParameterValueException("Unable to find zone: " + dataCenterId); -// } -// -// ServiceOfferingVO offering = _offeringsDao.findById(serviceOfferingId); -// if (offering == null) { -// throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId); -// } -// -// VMTemplateVO template = _templateDao.findById(templateId); -// // Make sure a valid template ID was specified -// if (template == null) { -// throw new InvalidParameterValueException("Please specify a valid template or ISO ID."); -// } -// -// boolean isIso = Storage.ImageFormat.ISO.equals(template.getFormat()); -// -// if (isIso && !template.isBootable()) { -// throw new InvalidParameterValueException("Please specify a bootable ISO."); -// } -// -// // If the template represents an ISO, a disk offering must be passed in, and will be used to create the root disk -// // Else, a disk offering is optional, and if present will be used to create the data disk -// DiskOfferingVO diskOffering = null; -// -// if (diskOfferingId != null) { -// diskOffering = _diskOfferingDao.findById(diskOfferingId); -// } -// -// if (isIso && diskOffering == null) { -// throw new InvalidParameterValueException("Please specify a valid disk offering ID."); -// } -// -// // validate that the template is usable by the account -// if (!template.isPublicTemplate()) { -// Long templateOwner = template.getAccountId(); -// if (!BaseCmd.isAdmin(account.getType()) && ((templateOwner == null) || (templateOwner.longValue() != accountId))) { -// // since the current account is not the owner of the template, check the launch permissions table to see if the -// // account can launch a VM from this template -// LaunchPermissionVO permission = _launchPermissionDao.findByTemplateAndAccount(templateId, account.getId()); -// if (permission == null) { -// throw new PermissionDeniedException("Account " + account.getAccountName() + " does not have permission to launch instances from template " + template.getName()); -// } -// } -// } -// -// byte [] decodedUserData = null; -// if (userData != null) { -// if (userData.length() >= 2* UserVmManager.MAX_USER_DATA_LENGTH_BYTES) { -// throw new InvalidParameterValueException("User data is too long"); -// } -// decodedUserData = org.apache.commons.codec.binary.Base64.decodeBase64(userData.getBytes()); -// if (decodedUserData.length > UserVmManager.MAX_USER_DATA_LENGTH_BYTES){ -// throw new InvalidParameterValueException("User data is too long"); -// } -// if (decodedUserData.length < 1) { -// throw new InvalidParameterValueException("User data is too short"); -// } -// -// } -// if (offering.getGuestIpType() != NetworkOffering.GuestIpType.Virtualized) { -// _networkGroupMgr.createDefaultNetworkGroup(accountId); -// } -// -// if (networkGroups != null) { -// if (offering.getGuestIpType() == NetworkOffering.GuestIpType.Virtualized) { -// throw new InvalidParameterValueException("Network groups are not compatible with service offering " + offering.getName()); -// } -// Set nameSet = new HashSet(); //handle duplicate names -- allowed -// nameSet.addAll(Arrays.asList(networkGroups)); -// nameSet.add(NetworkGroupManager.DEFAULT_GROUP_NAME); -// networkGroups = nameSet.toArray(new String[nameSet.size()]); -// List networkGroupVOs = _networkSecurityGroupDao.findByAccountAndNames(accountId, networkGroups); -// if (networkGroupVOs.size() != nameSet.size()) { -// throw new InvalidParameterValueException("Some network group names do not exist"); -// } -// } else { //create a default group if necessary -// if (offering.getGuestIpType() != NetworkOffering.GuestIpType.Virtualized && _networkGroupsEnabled) { -// networkGroups = new String[]{NetworkGroupManager.DEFAULT_GROUP_NAME}; -// } -// } -// -// Long eventId = cmd.getStartEventId(); -// try { -// return deployVirtualMachineImpl(userId, accountId, dataCenterId, serviceOfferingId, templateId, diskOfferingId, domain, password, displayName, group, userData, networkGroups, eventId, size); -// } catch (ResourceAllocationException e) { -// if(s_logger.isDebugEnabled()) -// s_logger.debug("Unable to deploy VM: " + e.getMessage()); -// EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_CREATE, "Unable to deploy VM: VM_INSUFFICIENT_CAPACITY", null, eventId); -// throw e; -// } catch (ExecutionException e) { -// if(s_logger.isDebugEnabled()) -// s_logger.debug("Unable to deploy VM: " + e.getMessage()); -// EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_CREATE, "Unable to deploy VM: VM_HOST_LICENSE_EXPIRED", null, eventId); -// throw e; -// } catch (InvalidParameterValueException e) { -// if(s_logger.isDebugEnabled()) -// s_logger.debug("Unable to deploy VM: " + e.getMessage()); -// EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_CREATE, "Unable to deploy VM: VM_INVALID_PARAM_ERROR", null, eventId); -// throw e; -// } catch (InternalErrorException e) { -// if(s_logger.isDebugEnabled()) -// s_logger.debug("Unable to deploy VM: " + e.getMessage()); -// EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_CREATE, "Unable to deploy VM: INTERNAL_ERROR", null, eventId); -// throw e; -// } catch (InsufficientStorageCapacityException e) { -// if(s_logger.isDebugEnabled()) -// s_logger.debug("Unable to deploy VM: " + e.getMessage()); -// EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_CREATE, "Unable to deploy VM: VM_INSUFFICIENT_CAPACITY", null, eventId); -// throw e; -// } catch (PermissionDeniedException e) { -// if(s_logger.isDebugEnabled()) -// s_logger.debug("Unable to deploy VM: " + e.getMessage()); -// EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_CREATE, "Unable to deploy VM: ACCOUNT_ERROR", null, eventId); -// throw e; -// } catch (ConcurrentOperationException e) { -// if(s_logger.isDebugEnabled()) -// s_logger.debug("Unable to deploy VM: " + e.getMessage()); -// EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_CREATE, "Unable to deploy VM: INTERNAL_ERROR", null, eventId); -// throw e; -// } catch(Exception e) { -// s_logger.warn("Unable to deploy VM : " + e.getMessage(), e); -// EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_CREATE, "Unable to deploy VM: INTERNAL_ERROR", null, eventId); -// throw new CloudRuntimeException("Unable to deploy VM : " + e.getMessage()); -// } - return null; + Account caller = UserContext.current().getAccount(); + + Domain domain = _domainDao.findById(cmd.getDomainId()); + if (domain == null || domain.getRemoved() != null) { + throw new InvalidParameterValueException("Unable to find domain: " + cmd.getDomainId()); + } + + _accountMgr.checkAccess(caller, domain); + + AccountVO owner = _accountDao.findById(cmd.getAccountId()); + if (owner == null || owner.getRemoved() != null) { + throw new InvalidParameterValueException("Unable to find account: " + cmd.getAccountId()); + } + + DataCenterVO dc = _dcDao.findById(cmd.getZoneId()); + if (dc == null) { + throw new InvalidParameterValueException("Unable to find zone: " + cmd.getZoneId()); + } + + ServiceOfferingVO offering = _serviceOfferingDao.findById(cmd.getServiceOfferingId()); + if (offering == null || offering.getRemoved() != null) { + throw new InvalidParameterValueException("Unable to find service offering: " + cmd.getServiceOfferingId()); + } + + VMTemplateVO template = _templateDao.findById(cmd.getTemplateId()); + // Make sure a valid template ID was specified + if (template == null || template.getRemoved() != null) { + throw new InvalidParameterValueException("Unable to use template " + cmd.getTemplateId()); + } + boolean isIso = Storage.ImageFormat.ISO == template.getFormat(); + if (isIso && !template.isBootable()) { + throw new InvalidParameterValueException("Installing from ISO requires an ISO that is bootable: " + template.getId()); + } + + // If the template represents an ISO, a disk offering must be passed in, and will be used to create the root disk + // Else, a disk offering is optional, and if present will be used to create the data disk + Pair rootDiskOffering = new Pair(null, null); + List> dataDiskOfferings = new ArrayList>(); + + if (isIso) { + if (cmd.getDiskOfferingId() == null) { + throw new InvalidParameterValueException("Installing from ISO requires a disk offering to be specified for the root disk."); + } + DiskOfferingVO diskOffering = _diskOfferingDao.findById(cmd.getDiskOfferingId()); + if (diskOffering == null) { + throw new InvalidParameterValueException("Unable to find disk offering " + cmd.getDiskOfferingId()); + } + Long size = null; + if (diskOffering.getDiskSize() == 0) { + size = cmd.getSize(); + if (size == null) { + throw new InvalidParameterValueException("Disk offering " + diskOffering + " requires size parameter."); + } + } + rootDiskOffering.first(diskOffering); + rootDiskOffering.second(size); + } else { + rootDiskOffering.first(offering); + if (cmd.getDiskOfferingId() != null) { + DiskOfferingVO diskOffering = _diskOfferingDao.findById(cmd.getDiskOfferingId()); + if (diskOffering == null) { + throw new InvalidParameterValueException("Unable to find disk offering " + cmd.getDiskOfferingId()); + } + Long size = null; + if (diskOffering.getDiskSize() == 0) { + size = cmd.getSize(); + if (size == null) { + throw new InvalidParameterValueException("Disk offering " + diskOffering + " requires size parameter."); + } + } + dataDiskOfferings.add(new Pair(diskOffering, size)); + } + } + + // Check that the password was passed in and is valid + String password = PasswordGenerator.generateRandomPassword(); + if (!template.getEnablePassword()) { + password = "saved_password"; + } + if (password == null || password.equals("") || (!validPassword(password))) { + throw new InvalidParameterValueException("A valid password for this virtual machine was not provided."); + } + + String networkDomain = null; + if (networkDomain == null) { + networkDomain = "v" + Long.toHexString(owner.getId()) + _defaultNetworkDomain; + } + + String userData = cmd.getUserData(); + byte [] decodedUserData = null; + if (userData != null) { + if (userData.length() >= 2 * MAX_USER_DATA_LENGTH_BYTES) { + throw new InvalidParameterValueException("User data is too long"); + } + decodedUserData = org.apache.commons.codec.binary.Base64.decodeBase64(userData.getBytes()); + if (decodedUserData.length > MAX_USER_DATA_LENGTH_BYTES){ + throw new InvalidParameterValueException("User data is too long"); + } + if (decodedUserData.length < 1) { + throw new InvalidParameterValueException("User data is too short"); + } + } + + _accountMgr.checkAccess(caller, template); + + DataCenterDeployment plan = new DataCenterDeployment(dc.getId(), 1); + + long id = _vmDao.getNextInSequence(Long.class, "id"); + + UserVmVO vm = new UserVmVO(id, VirtualMachineName.getVmName(id, owner.getId(), _instance), cmd.getDisplayName(), + template.getId(), template.getGuestOSId(), offering.getOfferHA(), domain.getId(), owner.getId(), offering.getId(), userData); + + s_logger.debug("Allocating in the DB for vm"); + + Transaction txn = Transaction.currentTxn(); + txn.start(); + vm = _vmDao.persist(vm); + + List configs = _networkMgr.setupNetworkConfiguration(owner, offering, plan); + List> networks = new ArrayList>(); + for (NetworkConfigurationVO config : configs) { + networks.add(new Pair(config, null)); + } + + if (_itMgr.allocate(vm, template, offering, rootDiskOffering, dataDiskOfferings, networks, plan, owner) == null) { + return null; + } + + txn.commit(); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Successfully allocated DB entry for " + vm); + } + return vm; } @Override - public UserVm startVirtualMachine(DeployVm2Cmd cmd) { + public UserVm startVirtualMachine(DeployVm2Cmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { + long vmId = cmd.getId(); + UserVmVO vm = _vmDao.findById(vmId); - return null; + long dcId = cmd.getZoneId(); + DataCenterDeployment plan = new DataCenterDeployment(dcId, 1); + + AccountVO owner = _accountDao.findById(vm.getAccountId()); + + return _itMgr.start(vm, plan, owner, this); } + + @Override + public boolean finalizeDeployment(Commands cmds, UserVmVO vm, VirtualMachineProfile profile, DeployDestination dest) { + return true; + } + + @Override + public boolean processDeploymentResult(Commands cmds, UserVmVO vm, VirtualMachineProfile profile, DeployDestination dest) { + return true; + } } diff --git a/server/src/com/cloud/vm/VirtualMachineGuru.java b/server/src/com/cloud/vm/VirtualMachineGuru.java index ead31b4fd8d..2bda52a8838 100644 --- a/server/src/com/cloud/vm/VirtualMachineGuru.java +++ b/server/src/com/cloud/vm/VirtualMachineGuru.java @@ -42,5 +42,5 @@ public interface VirtualMachineGuru { * @param dest destination it was sent to. * @return true if deployment was fine; false if it didn't go well. */ - boolean checkDeploymentResult(Commands cmds, T vm, VirtualMachineProfile profile, DeployDestination dest); + boolean processDeploymentResult(Commands cmds, T vm, VirtualMachineProfile profile, DeployDestination dest); } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 2e292ce6133..3f2b97dff4d 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -155,6 +155,7 @@ CREATE TABLE `cloud`.`network_offerings` ( `traffic_type` varchar(32) NOT NULL COMMENT 'traffic type carried on this network', `tags` varchar(4096) COMMENT 'tags supported by this offering', `system_only` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'Is this network offering for system use only', + `service_offering_id` bigint unsigned UNIQUE COMMENT 'service offering id that this network offering is tied to', `created` datetime NOT NULL COMMENT 'time the entry was created', `removed` datetime DEFAULT NULL COMMENT 'time the entry was removed', PRIMARY KEY (`id`) diff --git a/utils/src/com/cloud/utils/db/GenericDao.java b/utils/src/com/cloud/utils/db/GenericDao.java index da785808dd6..530da65469f 100755 --- a/utils/src/com/cloud/utils/db/GenericDao.java +++ b/utils/src/com/cloud/utils/db/GenericDao.java @@ -46,6 +46,8 @@ public interface GenericDao { **/ T findById(ID id); + T findByIdIncludingRemoved(ID id); + T findById(ID id, boolean fresh); /** diff --git a/utils/src/com/cloud/utils/db/GenericDaoBase.java b/utils/src/com/cloud/utils/db/GenericDaoBase.java index 3f36d69789a..13baf4066c5 100755 --- a/utils/src/com/cloud/utils/db/GenericDaoBase.java +++ b/utils/src/com/cloud/utils/db/GenericDaoBase.java @@ -780,6 +780,11 @@ public abstract class GenericDaoBase implements Gene } } + @Override @DB(txn=false) + public T findByIdIncludingRemoved(ID id) { + return findById(id, true, null); + } + @Override @DB(txn=false) public T findById(final ID id, boolean fresh) { if(!fresh) @@ -793,14 +798,21 @@ public abstract class GenericDaoBase implements Gene @Override public T lock(ID id, Boolean lock) { - String sql = _selectByIdSql; + return findById(id, false, lock); + } + + protected T findById(ID id, boolean removed, Boolean lock) { + StringBuilder sql = new StringBuilder(_selectByIdSql); + if (!removed) { + sql.append(" AND ").append(_removed.first()); + } if (lock != null) { - sql += lock ? FOR_UPDATE_CLAUSE : SHARE_MODE_CLAUSE; + sql.append(lock ? FOR_UPDATE_CLAUSE : SHARE_MODE_CLAUSE); } Transaction txn = Transaction.currentTxn(); PreparedStatement pstmt = s_initStmt; try { - pstmt = txn.prepareAutoCloseStatement(sql); + pstmt = txn.prepareAutoCloseStatement(sql.toString()); if (_idField.getAnnotation(EmbeddedId.class) == null) { pstmt.setObject(1, id); @@ -810,9 +822,7 @@ public abstract class GenericDaoBase implements Gene return rs.next() ? toEntityBean(rs, true) : null; } catch (SQLException e) { throw new CloudRuntimeException("DB Exception on: " + pstmt.toString(), e); - } catch (Throwable e) { - throw new CloudRuntimeException("Caught: " + pstmt.toString(), e); - } + } } @Override @DB(txn=false)