diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java index 7f9d79c65bc..8e7a15e7757 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java @@ -137,7 +137,7 @@ import com.cloud.agent.api.storage.CreatePrivateTemplateCommand; import com.cloud.agent.api.storage.DestroyCommand; import com.cloud.agent.api.storage.DownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; -import com.cloud.agent.api.to.StoragePoolTO; +import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.agent.api.to.VolumeTO; import com.cloud.agent.resource.computing.LibvirtStoragePoolDef.poolType; import com.cloud.agent.resource.computing.LibvirtStorageVolumeDef.volFormat; @@ -1173,7 +1173,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } protected Answer execute(CreateCommand cmd) { - StoragePoolTO pool = cmd.getPool(); + StorageFilerTO pool = cmd.getPool(); DiskProfile dskch = cmd.getDiskCharacteristics(); StorageVol tmplVol = null; StoragePool primaryPool = null; diff --git a/core/src/com/cloud/agent/api/Answer.java b/api/src/com/cloud/agent/api/Answer.java similarity index 100% rename from core/src/com/cloud/agent/api/Answer.java rename to api/src/com/cloud/agent/api/Answer.java diff --git a/core/src/com/cloud/agent/api/Command.java b/api/src/com/cloud/agent/api/Command.java similarity index 100% rename from core/src/com/cloud/agent/api/Command.java rename to api/src/com/cloud/agent/api/Command.java diff --git a/core/src/com/cloud/agent/api/UnsupportedAnswer.java b/api/src/com/cloud/agent/api/UnsupportedAnswer.java similarity index 100% rename from core/src/com/cloud/agent/api/UnsupportedAnswer.java rename to api/src/com/cloud/agent/api/UnsupportedAnswer.java diff --git a/core/src/com/cloud/agent/api/storage/CreateCommand.java b/api/src/com/cloud/agent/api/storage/CreateCommand.java similarity index 70% rename from core/src/com/cloud/agent/api/storage/CreateCommand.java rename to api/src/com/cloud/agent/api/storage/CreateCommand.java index d53e378aec7..46eae20a601 100644 --- a/core/src/com/cloud/agent/api/storage/CreateCommand.java +++ b/api/src/com/cloud/agent/api/storage/CreateCommand.java @@ -18,19 +18,16 @@ package com.cloud.agent.api.storage; import com.cloud.agent.api.Command; -import com.cloud.agent.api.to.StoragePoolTO; -import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.VolumeVO; +import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.storage.StoragePool; import com.cloud.vm.DiskProfile; -import com.cloud.vm.VMInstanceVO; public class CreateCommand extends Command { private long volId; - private StoragePoolTO pool; + private StorageFilerTO pool; private DiskProfile diskCharacteristics; private String templateUrl; private long size; - private String instanceName; protected CreateCommand() { super(); @@ -45,8 +42,8 @@ public class CreateCommand extends Command { * @param templateUrl * @param pool */ - public CreateCommand(VolumeVO vol, VMInstanceVO vm, DiskProfile diskCharacteristics, String templateUrl, StoragePoolVO pool) { - this(vol, vm, diskCharacteristics, pool, 0); + public CreateCommand(DiskProfile diskCharacteristics, String templateUrl, StorageFilerTO pool) { + this(diskCharacteristics, pool, 0); this.templateUrl = templateUrl; } @@ -58,13 +55,20 @@ public class CreateCommand extends Command { * @param diskCharacteristics * @param pool */ - public CreateCommand(VolumeVO vol, VMInstanceVO vm, DiskProfile diskCharacteristics, StoragePoolVO pool, long size) { - this.volId = vol.getId(); + public CreateCommand(DiskProfile diskCharacteristics, StorageFilerTO pool, long size) { + this.volId = diskCharacteristics.getVolumeId(); this.diskCharacteristics = diskCharacteristics; - this.pool = new StoragePoolTO(pool); + this.pool = pool; this.templateUrl = null; this.size = size; - //this.instanceName = vm.getInstanceName(); + } + + public CreateCommand(DiskProfile diskCharacteristics, String templateUrl, StoragePool pool) { + this(diskCharacteristics, templateUrl, new StorageFilerTO(pool)); + } + + public CreateCommand(DiskProfile diskCharacteristics, StoragePool pool, long size) { + this(diskCharacteristics, new StorageFilerTO(pool), size); } @Override @@ -76,7 +80,7 @@ public class CreateCommand extends Command { return templateUrl; } - public StoragePoolTO getPool() { + public StorageFilerTO getPool() { return pool; } @@ -92,7 +96,8 @@ public class CreateCommand extends Command { return this.size; } + @Deprecated public String getInstanceName() { - return instanceName; + return null; } } diff --git a/core/src/com/cloud/agent/api/to/StoragePoolTO.java b/api/src/com/cloud/agent/api/to/StorageFilerTO.java similarity index 92% rename from core/src/com/cloud/agent/api/to/StoragePoolTO.java rename to api/src/com/cloud/agent/api/to/StorageFilerTO.java index 188dc1c8094..f59ca841aa4 100644 --- a/core/src/com/cloud/agent/api/to/StoragePoolTO.java +++ b/api/src/com/cloud/agent/api/to/StorageFilerTO.java @@ -17,11 +17,10 @@ */ package com.cloud.agent.api.to; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePool; - -public class StoragePoolTO { +public class StorageFilerTO { long id; String uuid; String host; @@ -29,7 +28,7 @@ public class StoragePoolTO { int port; StoragePoolType type; - public StoragePoolTO(StoragePoolVO pool) { + public StorageFilerTO(StoragePool pool) { this.id = pool.getId(); this.host = pool.getHostAddress(); this.port = pool.getPort(); @@ -62,7 +61,7 @@ public class StoragePoolTO { return type; } - protected StoragePoolTO() { + protected StorageFilerTO() { } @Override diff --git a/api/src/com/cloud/exception/StorageUnavailableException.java b/api/src/com/cloud/exception/StorageUnavailableException.java index d6ed0265d88..1015e65835e 100644 --- a/api/src/com/cloud/exception/StorageUnavailableException.java +++ b/api/src/com/cloud/exception/StorageUnavailableException.java @@ -20,18 +20,39 @@ package com.cloud.exception; import com.cloud.utils.SerialVersionUID; /** - * This exception is thrown when the storage device can not be reached. - * + * This exception is thrown when storage for a VM is unavailable. + * If the cause is due to storage pool unavailable, calling + * getOffendingObject() will return the object that we have + * problem with. + * */ -public class StorageUnavailableException extends AgentUnavailableException { +public class StorageUnavailableException extends Exception { + Object _obj; private static final long serialVersionUID = SerialVersionUID.StorageUnavailableException; - public StorageUnavailableException(long hostId) { - super(hostId); - } - public StorageUnavailableException(String msg) { - super(msg, -1); + super(msg); + } + + public StorageUnavailableException(String msg, Throwable cause) { + super(msg, cause); + } + + public StorageUnavailableException(String msg, Object cause) { + super(msg); + _obj = cause; + } + + public StorageUnavailableException(String msg, Object obj, Throwable cause) { + super(msg, cause); + _obj = obj; + } + + /** + * @return object that caused this problem. It can either be a StoragePool or volume. + */ + public Object getOffendingObject() { + return _obj; } } diff --git a/api/src/com/cloud/network/NetworkConfiguration.java b/api/src/com/cloud/network/NetworkConfiguration.java index 9ccf426a389..760e7ce2e13 100644 --- a/api/src/com/cloud/network/NetworkConfiguration.java +++ b/api/src/com/cloud/network/NetworkConfiguration.java @@ -23,10 +23,10 @@ public interface NetworkConfiguration { } enum State implements FiniteState { - Allocated, // Indicates the network configuration is in allocated but not setup. - Setup, // Indicates the network configuration is setup. - Implemented, // Indicates the network configuration is in use. - Destroying; + Allocated("Indicates the network configuration is in allocated but not setup"), + Setup("Indicates the network configuration is setup"), + Implemented("Indicates the network configuration is in use"), + Destroying("Indicates the network configuration is being destroyed"); @Override public StateMachine getStateMachine() { @@ -48,7 +48,23 @@ public interface NetworkConfiguration { return s_fsm.getPossibleEvents(this); } + String _description; + + @Override + public String getDescription() { + return _description; + } + + private State(String description) { + _description = description; + } + private static StateMachine s_fsm = new StateMachine(); + static { + s_fsm.addTransition(State.Allocated, Event.ImplementNetwork, State.Implemented); + s_fsm.addTransition(State.Implemented, Event.DestroyNetwork, State.Destroying); + } + } diff --git a/api/src/com/cloud/resource/Resource.java b/api/src/com/cloud/resource/Resource.java index 310507061ae..3cc5135c648 100644 --- a/api/src/com/cloud/resource/Resource.java +++ b/api/src/com/cloud/resource/Resource.java @@ -26,12 +26,14 @@ public interface Resource { } enum State implements FiniteState { - Allocated, // Resource is allocated - Reserving, // Resource is being reserved right now. - Reserved, // Resource is reserved - Releasing, // Resource is being released. - Ready; // Resource is ready which means it does not need to go through reservation. + Allocated("Resource is allocated but not reserved"), + Reserving("Resource is being reserved right now"), + Reserved("Resource has been reserved."), + Releasing("Resource is being released"), + Ready("Resource is ready which means it doesn't need to go through resservation"); + String _description; + @Override public StateMachine getStateMachine() { @@ -54,12 +56,24 @@ public interface Resource { return s_fsm.getPossibleEvents(this); } + private State(String description) { + _description = description; + } + + @Override + public String getDescription() { + return _description; + } + final static private StateMachine s_fsm = new StateMachine(); static { s_fsm.addTransition(State.Allocated, Event.ReservationRequested, State.Reserving); s_fsm.addTransition(State.Reserving, Event.CancelRequested, State.Allocated); s_fsm.addTransition(State.Reserving, Event.OperationCompleted, State.Reserved); s_fsm.addTransition(State.Reserving, Event.OperationFailed, State.Allocated); + s_fsm.addTransition(State.Reserved, Event.ReleaseRequested, State.Releasing); + s_fsm.addTransition(State.Releasing, Event.OperationCompleted, State.Allocated); + s_fsm.addTransition(State.Releasing, Event.OperationFailed, State.Reserved); } } diff --git a/api/src/com/cloud/storage/StorageGuru.java b/api/src/com/cloud/storage/StorageGuru.java new file mode 100644 index 00000000000..396013debf5 --- /dev/null +++ b/api/src/com/cloud/storage/StorageGuru.java @@ -0,0 +1,30 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.storage; + +import com.cloud.utils.component.Adapter; + +/** + * StorageGuru understands about how to implement different + * types of storage pools. + */ +public interface StorageGuru extends Adapter { + void createVolume(); + void prepareVolume(); + void destroyVolume(); +} diff --git a/api/src/com/cloud/storage/StoragePool.java b/api/src/com/cloud/storage/StoragePool.java index 2c06aba7628..dbbb8c61492 100644 --- a/api/src/com/cloud/storage/StoragePool.java +++ b/api/src/com/cloud/storage/StoragePool.java @@ -101,4 +101,8 @@ public interface StoragePool { * @return the storage pool status */ Status getStatus(); + + int getPort(); + + Long getPodId(); } diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java index 75421e1880b..15333865c20 100755 --- a/api/src/com/cloud/storage/Volume.java +++ b/api/src/com/cloud/storage/Volume.java @@ -18,10 +18,14 @@ package com.cloud.storage; import java.util.Date; +import java.util.List; +import java.util.Set; import com.cloud.domain.PartOf; 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 { @@ -29,14 +33,70 @@ public interface Volume extends PartOf, OwnedBy, BasedOn { enum MirrorState {NOT_MIRRORED, ACTIVE, DEFUNCT}; - enum State { - Allocated, - Creating, - Created, - Corrupted, - ToBeDestroyed, - Expunging, - Destroyed + enum State implements FiniteState { + Allocated("The volume is allocated but has not been created yet."), + Creating("The volume is being created. getPoolId() should reflect the pool where it is being created."), + Ready("The volume is ready to be used."), + Destroy("The volume is set to be desctroyed but can be recovered."), + Expunging("The volume is being destroyed. There's no way to recover."), + Destroyed("The volume is destroyed. Should be removed."); + + String _description; + + private State(String description) { + _description = description; + } + + @Override + public StateMachine getStateMachine() { + return s_fsm; + } + + @Override + public State getNextState(Event event) { + return s_fsm.getNextState(this, event); + } + + @Override + public List getFromStates(Event event) { + return s_fsm.getFromStates(this, event); + } + + @Override + public Set getPossibleEvents() { + return s_fsm.getPossibleEvents(this); + } + + @Override + public String getDescription() { + return _description; + } + + private final static StateMachine s_fsm = new StateMachine(); + static { + s_fsm.addTransition(Allocated, Event.Create, Creating); + s_fsm.addTransition(Allocated, Event.Destroy, Destroyed); + s_fsm.addTransition(Creating, Event.OperationRetry, Creating); + s_fsm.addTransition(Creating, Event.OperationFailed, Allocated); + s_fsm.addTransition(Creating, Event.OperationSucceeded, Ready); + s_fsm.addTransition(Creating, Event.Destroy, Expunging); + s_fsm.addTransition(Ready, Event.Destroy, Destroy); + s_fsm.addTransition(Destroy, Event.Expunge, Expunging); + s_fsm.addTransition(Destroy, Event.Recover, Ready); + s_fsm.addTransition(Expunging, Event.OperationSucceeded, Destroyed); + s_fsm.addTransition(Expunging, Event.OperationFailed, Destroy); + s_fsm.addTransition(Allocated, Event.Destroy, Destroyed); + } + } + + enum Event { + Create, + OperationFailed, + OperationSucceeded, + OperationRetry, + Destroy, + Recover, + Expunge; } enum SourceType { diff --git a/api/src/com/cloud/vm/State.java b/api/src/com/cloud/vm/State.java index 53bd798818f..c024ff270b9 100644 --- a/api/src/com/cloud/vm/State.java +++ b/api/src/com/cloud/vm/State.java @@ -26,21 +26,28 @@ import com.cloud.utils.fsm.StateMachine; import com.cloud.vm.VirtualMachine.Event; public enum State implements FiniteState { - Creating(true), - Starting(true), - Running(false), - Stopping(true), - Stopped(false), - Destroyed(false), - Expunging(true), - Migrating(true), - Error(false), - Unknown(false); + Creating(true, "VM is being created"), + Starting(true, "VM is being started. At this state, you should find host id filled which means it's being started on that host."), + Running(false, "VM is running. host id has the host that it is running on."), + Stopping(true, "VM is being stopped. host id has the host that it is being stopped on."), + Stopped(false, "VM is stopped. host id should be null."), + Destroyed(false, "VM is marked for destroy."), + Expunging(true, "VM is being expunged."), + Migrating(true, "VM is being migrated. host id holds to from host"), + Error(false, "VM is in error"), + Unknown(false, "VM state is unknown."); private final boolean _transitional; + String _description; - private State(boolean transitional) { + private State(boolean transitional, String description) { _transitional = transitional; + _description = description; + } + + @Override + public String getDescription() { + return _description; } public boolean isTransitional() { @@ -67,6 +74,7 @@ public enum State implements FiniteState { return s_fsm; } + protected static final StateMachine s_fsm = new StateMachine(); static { s_fsm.addTransition(null, VirtualMachine.Event.CreateRequested, State.Creating); diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 4e9c7e7ca59..0bef5d1f407 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -145,7 +145,7 @@ import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.storage.ShareAnswer; import com.cloud.agent.api.storage.ShareCommand; import com.cloud.agent.api.to.NicTO; -import com.cloud.agent.api.to.StoragePoolTO; +import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VolumeTO; import com.cloud.exception.InternalErrorException; @@ -4449,7 +4449,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR protected Answer execute(ModifyStoragePoolCommand cmd) { StoragePoolVO pool = cmd.getPool(); - StoragePoolTO poolTO = new StoragePoolTO(pool); + StorageFilerTO poolTO = new StorageFilerTO(pool); try { Connection conn = getConnection(); @@ -4478,7 +4478,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR protected Answer execute(DeleteStoragePoolCommand cmd) { StoragePoolVO pool = cmd.getPool(); - StoragePoolTO poolTO = new StoragePoolTO(pool); + StorageFilerTO poolTO = new StorageFilerTO(pool); try { Connection conn = getConnection(); SR sr = getStorageRepository(conn, poolTO); @@ -4719,7 +4719,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR @Override public CreateAnswer execute(CreateCommand cmd) { - StoragePoolTO pool = cmd.getPool(); + StorageFilerTO pool = cmd.getPool(); DiskProfile dskch = cmd.getDiskCharacteristics(); VDI vdi = null; @@ -4893,7 +4893,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR } } - protected SR getIscsiSR(StoragePoolTO pool) { + protected SR getIscsiSR(StorageFilerTO pool) { Connection conn = getConnection(); synchronized (pool.getUuid().intern()) { Map deviceConfig = new HashMap(); @@ -5003,7 +5003,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR } } - protected SR getNfsSR(StoragePoolTO pool) { + protected SR getNfsSR(StorageFilerTO pool) { Connection conn = getConnection(); Map deviceConfig = new HashMap(); @@ -5124,7 +5124,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR public CopyVolumeAnswer execute(final CopyVolumeCommand cmd) { String volumeUUID = cmd.getVolumePath(); StoragePoolVO pool = cmd.getPool(); - StoragePoolTO poolTO = new StoragePoolTO(pool); + StorageFilerTO poolTO = new StorageFilerTO(pool); String secondaryStorageURL = cmd.getSecondaryStorageURL(); URI uri = null; @@ -6041,7 +6041,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR } } - protected SR getStorageRepository(Connection conn, StoragePoolTO pool) { + protected SR getStorageRepository(Connection conn, StorageFilerTO pool) { Set srs; try { srs = SR.getByNameLabel(conn, pool.getUuid()); diff --git a/core/src/com/cloud/storage/StorageManager.java b/core/src/com/cloud/storage/StorageManager.java index d7bda8cb9ed..e75267963a7 100755 --- a/core/src/com/cloud/storage/StorageManager.java +++ b/core/src/com/cloud/storage/StorageManager.java @@ -28,6 +28,8 @@ import com.cloud.agent.api.to.VolumeTO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientStorageCapacityException; import com.cloud.exception.InternalErrorException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceInUseException; @@ -229,9 +231,9 @@ public interface StorageManager extends Manager { */ boolean volumeOnSharedStoragePool(VolumeVO volume); - Answer[] sendToPool(StoragePoolVO pool, Command[] cmds, boolean stopOnError); + Answer[] sendToPool(StoragePool pool, Command[] cmds, boolean stopOnError); - Answer sendToPool(StoragePoolVO pool, Command cmd); + Answer sendToPool(StoragePool pool, Command cmd); /** * Checks that one of the following is true: @@ -314,9 +316,9 @@ public interface StorageManager extends Manager { DiskProfile allocateTemplatedVolume(VolumeType type, String name, DiskOfferingVO offering, VMTemplateVO template, T vm, AccountVO owner); void create(T vm); - Long findHostIdForStoragePool(StoragePoolVO pool); + Long findHostIdForStoragePool(StoragePool pool); void createCapacityEntry(StoragePoolVO storagePool, long allocated); - VolumeTO[] prepare(VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException; + VolumeTO[] prepare(VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException, ConcurrentOperationException; } diff --git a/core/src/com/cloud/storage/StoragePoolVO.java b/core/src/com/cloud/storage/StoragePoolVO.java index f3a3460157c..7d3a8b90724 100644 --- a/core/src/com/cloud/storage/StoragePoolVO.java +++ b/core/src/com/cloud/storage/StoragePoolVO.java @@ -82,7 +82,8 @@ public class StoragePoolVO implements StoragePool { @Enumerated(value=EnumType.STRING) private Status status; - public long getId() { + @Override + public long getId() { return id; } @@ -95,19 +96,23 @@ public class StoragePoolVO implements StoragePool { // TODO Auto-generated constructor stub } - public String getName() { + @Override + public String getName() { return name; } - public String getUuid() { + @Override + public String getUuid() { return uuid; } - public StoragePoolType getPoolType() { + @Override + public StoragePoolType getPoolType() { return poolType; } - public Date getCreated() { + @Override + public Date getCreated() { return created; } @@ -115,19 +120,23 @@ public class StoragePoolVO implements StoragePool { return removed; } - public Date getUpdateTime() { + @Override + public Date getUpdateTime() { return updateTime; } - public long getDataCenterId() { + @Override + public long getDataCenterId() { return dataCenterId; } - public long getAvailableBytes() { + @Override + public long getAvailableBytes() { return availableBytes; } - public long getCapacityBytes() { + @Override + public long getCapacityBytes() { return capacityBytes; } @@ -160,10 +169,12 @@ public class StoragePoolVO implements StoragePool { this.clusterId = clusterId; } + @Override public String getHostAddress() { return hostAddress; } + @Override public String getPath() { return path; } @@ -217,10 +228,12 @@ public class StoragePoolVO implements StoragePool { return port; } + @Override public boolean isShared() { return poolType.isShared(); } + @Override public boolean isLocal() { return !poolType.isShared(); } @@ -252,6 +265,10 @@ public class StoragePoolVO implements StoragePool { this.name = name; } + public boolean isInMaintenance() { + return status == Status.PrepareForMaintenance || status == Status.Maintenance || status == Status.ErrorInMaintenance || removed != null; + } + @Override public boolean equals(Object obj) { if (!(obj instanceof StoragePoolVO) || obj == null) { diff --git a/core/src/com/cloud/storage/VolumeVO.java b/core/src/com/cloud/storage/VolumeVO.java index d5d23dea53d..72b4f237635 100755 --- a/core/src/com/cloud/storage/VolumeVO.java +++ b/core/src/com/cloud/storage/VolumeVO.java @@ -236,6 +236,10 @@ public class VolumeVO implements Volume { this.status = AsyncInstanceCreateStatus.Created; this.recreatable = false; } + + public void setState(State state) { + this.state = state; + } public boolean isRecreatable() { return recreatable; @@ -245,7 +249,8 @@ public class VolumeVO implements Volume { return iscsiName; } - public long getId() { + @Override + public long getId() { return id; } diff --git a/core/src/com/cloud/storage/dao/VolumeDao.java b/core/src/com/cloud/storage/dao/VolumeDao.java index 3bd43faf9bc..22a84e0a85a 100755 --- a/core/src/com/cloud/storage/dao/VolumeDao.java +++ b/core/src/com/cloud/storage/dao/VolumeDao.java @@ -19,6 +19,7 @@ package com.cloud.storage.dao; import java.util.List; +import com.cloud.exception.ConcurrentOperationException; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.utils.Pair; @@ -47,4 +48,13 @@ public interface VolumeDao extends GenericDao { List findCreatedByInstance(long id); List findByPoolId(long poolId); List findByInstanceAndDeviceId(long instanceId, long deviceId); + List findUsableVolumesForInstance(long instanceId); + + /** + * Updates the volume only if the state in memory matches the state in the database. + * @param vol Volume to be updated. + * @param event event that causes the database change. + * @return true if update happened, false if not. + */ + boolean update(VolumeVO vol, Volume.Event event) throws ConcurrentOperationException; } diff --git a/core/src/com/cloud/storage/dao/VolumeDaoImpl.java b/core/src/com/cloud/storage/dao/VolumeDaoImpl.java index dc82102a1a5..d58444a9245 100755 --- a/core/src/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/core/src/com/cloud/storage/dao/VolumeDaoImpl.java @@ -29,11 +29,13 @@ import javax.ejb.Local; import org.apache.log4j.Logger; import com.cloud.async.AsyncInstanceCreateStatus; +import com.cloud.exception.ConcurrentOperationException; import com.cloud.storage.Volume; import com.cloud.storage.Volume.MirrorState; import com.cloud.storage.Volume.VolumeType; import com.cloud.storage.VolumeVO; import com.cloud.utils.Pair; +import com.cloud.utils.db.Attribute; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; @@ -42,6 +44,7 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.exception.CloudRuntimeException; @Local(value=VolumeDao.class) @DB(txn=false) @@ -62,6 +65,10 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol protected final SearchBuilder RemovedButNotDestroyedSearch; protected final SearchBuilder PoolIdSearch; protected final SearchBuilder InstanceAndDeviceIdSearch; + protected final SearchBuilder InstanceStatesSearch; + protected final SearchBuilder IdStateSearch; + + protected final Attribute _stateAttr; protected static final String SELECT_VM_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ? and v.mirror_state = ?"; protected static final String SELECT_VM_ID_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ?"; @@ -143,6 +150,15 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol return listBy(sc); } + @Override + public List findUsableVolumesForInstance(long instanceId) { + SearchCriteria sc = InstanceStatesSearch.create(); + sc.setParameters("instance", instanceId); + sc.setParameters("states", Volume.State.Creating, Volume.State.Ready, Volume.State.Allocated); + + return listBy(sc); + } + @Override public List findByInstanceAndType(long id, VolumeType vType) { SearchCriteria sc = InstanceAndTypeSearch.create(); @@ -271,6 +287,28 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol update(volumeId, volume); } + @Override + public boolean update(VolumeVO vol, Volume.Event event) throws ConcurrentOperationException { + Volume.State oldState = vol.getState(); + Volume.State newState = oldState.getNextState(event); + + assert newState != null : "Event "+ event + " cannot happen from " + oldState; + + UpdateBuilder builder = getUpdateBuilder(vol); + builder.set(vol, _stateAttr, newState); + + SearchCriteria sc = IdStateSearch.create(); + sc.setParameters("id", vol.getId()); + sc.setParameters("state", vol.getState()); + + int rows = update(builder, sc, null); + if (rows != 1) { + VolumeVO dbVol = findById(vol.getId()); + throw new ConcurrentOperationException("Unable to update " + vol + ": Old State=" + oldState + "; New State = " + newState + "; DB State=" + dbVol.getState()); + } + return rows == 1; + } + protected VolumeDaoImpl() { AccountIdSearch = createSearchBuilder(); AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); @@ -353,6 +391,19 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol RemovedButNotDestroyedSearch.and("destroyed", RemovedButNotDestroyedSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); RemovedButNotDestroyedSearch.and("removed", RemovedButNotDestroyedSearch.entity().getRemoved(), SearchCriteria.Op.NNULL); RemovedButNotDestroyedSearch.done(); + + InstanceStatesSearch = createSearchBuilder(); + InstanceStatesSearch.and("instance", InstanceStatesSearch.entity().getInstanceId(), SearchCriteria.Op.EQ); + InstanceStatesSearch.and("states", InstanceStatesSearch.entity().getState(), SearchCriteria.Op.IN); + InstanceStatesSearch.done(); + + IdStateSearch = createSearchBuilder(); + IdStateSearch.and("id", IdStateSearch.entity().getId(), SearchCriteria.Op.EQ); + IdStateSearch.and("state", IdStateSearch.entity().getState(), SearchCriteria.Op.EQ); + IdStateSearch.done(); + + _stateAttr = _allAttributes.get("state"); + assert _stateAttr != null : "Couldn't get the state attribute"; } @Override @DB(txn=false) diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 399c7795de3..9e41e39652d 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -516,7 +516,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach @Override public ConsoleProxyVO startProxy(long proxyVmId, long startEventId) { try { - return start(proxyVmId, startEventId); + return start2(proxyVmId, startEventId); } catch (StorageUnavailableException e) { s_logger.warn("Exception while trying to start console proxy", e); return null; @@ -852,7 +852,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach if (s_logger.isDebugEnabled()) s_logger.debug("Assign console proxy from a newly started instance for request from data center : " + dataCenterId); - Map context = createProxyInstance(dataCenterId); + Map context = createProxyInstance2(dataCenterId); long proxyVmId = (Long) context.get("proxyVmId"); if (proxyVmId == 0) { @@ -892,7 +892,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach if (s_logger.isDebugEnabled()) s_logger.debug("Assign console proxy from a newly started instance for request from data center : " + dataCenterId); - Map context = createProxyInstance(dataCenterId); + Map context = createProxyInstance2(dataCenterId); long proxyVmId = (Long) context.get("proxyVmId"); if (proxyVmId == 0) { @@ -1417,7 +1417,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach try { if (proxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { try { - readyProxy = start(readyProxy.getId(), 0); + readyProxy = start2(readyProxy.getId(), 0); } finally { proxyLock.unlock(); } @@ -2150,7 +2150,7 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach if (!_storageMgr.share(proxy, vols, routingHost, false)) { s_logger.warn("Can not share " + proxy.getName()); - throw new StorageUnavailableException(vol.getPoolId()); + throw new StorageUnavailableException("Can not share " + proxy.getName(), vol); } Answer answer = _agentMgr.easySend(routingHost.getId(), cmd); diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index ec603e50dc9..bd79579bdf1 100644 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -2139,7 +2139,7 @@ public class NetworkManagerImpl implements NetworkManager, VirtualMachineManager if( ! _storageMgr.share(router, vols, routingHost, false) ) { s_logger.warn("Can not share " + vol.getPath() + " to " + router.getName() ); - throw new StorageUnavailableException(vol.getPoolId()); + throw new StorageUnavailableException("Can not share " + vol.getPath() + " to " + router.getName(), vol); } final Answer answer = _agentMgr.easySend(routingHost.getId(), cmd); diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 0539b3a470b..1d344ac666e 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -26,7 +26,6 @@ import java.util.Enumeration; import java.util.Formatter; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -56,6 +55,7 @@ import com.cloud.agent.api.storage.CreateAnswer; import com.cloud.agent.api.storage.CreateCommand; import com.cloud.agent.api.storage.DeleteTemplateCommand; import com.cloud.agent.api.storage.DestroyCommand; +import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.agent.api.to.VolumeTO; import com.cloud.alert.AlertManager; import com.cloud.api.BaseCmd; @@ -84,6 +84,7 @@ import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.DiscoveryException; import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientStorageCapacityException; import com.cloud.exception.InternalErrorException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.OperationTimedoutException; @@ -103,6 +104,7 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.Volume.Event; import com.cloud.storage.Volume.MirrorState; import com.cloud.storage.Volume.SourceType; import com.cloud.storage.Volume.VolumeType; @@ -173,10 +175,6 @@ public class StorageManagerImpl implements StorageManager { @Inject protected ConsoleProxyDao _consoleProxyDao; @Inject protected DetailsDao _detailsDao; @Inject protected SnapshotDao _snapshotDao; - @Inject(adapter=StoragePoolAllocator.class) - protected Adapters _storagePoolAllocators; - @Inject(adapter=StoragePoolDiscoverer.class) - protected Adapters _discoverers; @Inject protected StoragePoolHostDao _storagePoolHostDao; @Inject protected AlertManager _alertMgr; @Inject protected VMTemplateHostDao _vmTemplateHostDao = null; @@ -197,6 +195,11 @@ public class StorageManagerImpl implements StorageManager { @Inject protected ServiceOfferingDao _offeringDao; @Inject protected UserDao _userDao; + @Inject(adapter=StoragePoolAllocator.class) + protected Adapters _storagePoolAllocators; + @Inject(adapter=StoragePoolDiscoverer.class) + protected Adapters _discoverers; + protected SearchBuilder HostTemplateStatesSearch; protected SearchBuilder PoolsUsedByVmSearch; @@ -272,79 +275,6 @@ public class StorageManagerImpl implements StorageManager { return vols.get(0); } - @Override - public VolumeTO[] prepare(VirtualMachineProfile vm, DeployDestination dest) { - List vols = _volsDao.findCreatedByInstance(vm.getId()); - List recreateVols = new ArrayList(vols.size()); - Host host = dest.getHost(); - - VolumeTO[] disks = new VolumeTO[vols.size()]; - int i = 0; - Iterator it = vols.iterator(); - while (it.hasNext()) { - VolumeVO vol = it.next(); - if (vol.isRecreatable()) { - it.remove(); - //if we have a system vm - //get the storage pool - //if pool is in maintenance - //add to recreate vols, and continue - if(vm.getType().equals(VirtualMachine.Type.ConsoleProxy) || vm.getType().equals(VirtualMachine.Type.DomainRouter) || vm.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) - { - StoragePoolVO sp = _storagePoolDao.findById(vol.getPoolId()); - - if(sp!=null && sp.getStatus().equals(Status.PrepareForMaintenance)) - { - recreateVols.add(vol); - continue; - } - } - - StoragePoolHostVO ph = _storagePoolHostDao.findByPoolHost(vol.getPoolId(), host.getId()); - if (ph == null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Must recreate " + vol + " since " + vol.getPoolId() + " has is not hooked up with host " + host.getId()); - } - recreateVols.add(vol); - } - } - } - - for (VolumeVO vol : recreateVols) { - VolumeVO create = allocateDuplicateVolume(vol); - vols.add(vol); - } - - /* - create.setDiskOfferingId(vol.getDiskOfferingId()); - create.setDeviceId(vol.getDeviceId()); - create = _volsDao.persist(create); - VMTemplateVO template = _templateDao.findById(create.getTemplateId()); - DataCenterVO dc = _dcDao.findById(create.getDataCenterId()); - HostPodVO pod = _podDao.findById(host.getPodId()); - DiskOfferingVO diskOffering = null; - diskOffering = _diskOfferingDao.findById(vol.getDiskOfferingId()); - ServiceOfferingVO offering; - if (vm instanceof UserVmVO) { - offering = _offeringDao.findById(((UserVmVO)vm).getServiceOfferingId()); - } else { - offering = _offeringDao.findById(vol.getDiskOfferingId()); - } - VolumeVO created = createVolume(create, vm, template, dc, pod, host.getClusterId(), offering, diskOffering, new ArrayList(),0); - if (created == null) { - break; - } - createds.add(created); - - for (VolumeVO vol : recreateVols) { - _volsDao.remove(vol.getId()); - } - disks[i++] = null; - } - */ - return disks; - } - VolumeVO allocateDuplicateVolume(VolumeVO oldVol) { VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), oldVol.getName(), oldVol.getDataCenterId(), oldVol.getDomainId(), oldVol.getAccountId(), oldVol.getDiskOfferingId(), oldVol.getSize()); newVol.setTemplateId(oldVol.getTemplateId()); @@ -487,7 +417,7 @@ public class StorageManagerImpl implements StorageManager { } @Override - public Long findHostIdForStoragePool(StoragePoolVO pool) { + public Long findHostIdForStoragePool(StoragePool pool) { List poolHosts = _poolHostDao.listByHostStatus(pool.getId(), Status.Up); if (poolHosts.size() == 0) { @@ -498,7 +428,7 @@ public class StorageManagerImpl implements StorageManager { } @Override - public Answer[] sendToPool(StoragePoolVO pool, Command[] cmds, boolean stopOnError) { + public Answer[] sendToPool(StoragePool pool, Command[] cmds, boolean stopOnError) { List poolHosts = _poolHostDao.listByHostStatus(pool.getId(), Status.Up); Collections.shuffle(poolHosts); @@ -520,7 +450,7 @@ public class StorageManagerImpl implements StorageManager { } @Override - public Answer sendToPool(StoragePoolVO pool, Command cmd) { + public Answer sendToPool(StoragePool pool, Command cmd) { Command[] cmds = new Command[]{cmd}; Answer[] answers = sendToPool(pool, cmds, true); if (answers == null) { @@ -885,9 +815,9 @@ public class StorageManagerImpl implements StorageManager { if (tmpltStoredOn == null) { continue; } - cmd = new CreateCommand(volume, vm, dskCh, tmpltStoredOn.getLocalDownloadPath(), pool); + cmd = new CreateCommand(dskCh, tmpltStoredOn.getLocalDownloadPath(), new StorageFilerTO(pool)); } else { - cmd = new CreateCommand(volume, vm, dskCh, pool, size); + cmd = new CreateCommand(dskCh, new StorageFilerTO(pool), size); } Answer answer = sendToPool(pool, cmd); @@ -2441,6 +2371,149 @@ public class StorageManagerImpl implements StorageManager { return createDiskCharacteristics(volume, offering); } + protected StoragePool findStorage(DiskProfile dskCh, DeployDestination dest, VirtualMachineProfile vm, List alreadyAllocated, Set avoid) { + for (StoragePoolAllocator allocator : _storagePoolAllocators) { + StoragePool pool = allocator.allocateTo(dskCh, vm, dest, alreadyAllocated, avoid); + if (pool != null) { + return pool; + } + } + return null; + } + + @Override + public VolumeTO[] prepare(VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException { + List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Preparing " + vols.size() + " volumes for " + vm); + } + + List recreateVols = new ArrayList(vols.size()); + VolumeTO[] disks = new VolumeTO[vols.size()]; + + int i = 0; + for (VolumeVO vol : vols) { + Volume.State state = vol.getState(); + if (state == Volume.State.Ready) { + StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); + if (pool.getRemoved() != null || pool.isInMaintenance()) { + if (vol.isRecreatable()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Volume " + vol + " has to be recreated due to storage pool " + pool + " is unavailable"); + } + recreateVols.add(vol); + } else { + throw new StorageUnavailableException("Volume " + vol + " is not available on the storage pool.", pool); + } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Volume " + vol + " is ready."); + } + disks[i++] = new VolumeTO(vol, pool); + } + } else if (state == Volume.State.Allocated) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating volume " + vol + " for the first time."); + } + recreateVols.add(vol); + } else { + throw new StorageUnavailableException("Volume " + vol + " can not be used", vol); + } + } + + for (VolumeVO vol : recreateVols) { + VolumeVO newVol; + if (vol.getState() == Volume.State.Allocated) { + newVol = vol; + } else { + newVol = switchVolume(vol); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Created new volume " + newVol + " for old volume " + vol); + } + } + + try { + _volsDao.update(newVol, Volume.Event.Create); + } catch(ConcurrentOperationException e) { + throw new StorageUnavailableException("Unable to create " + newVol, newVol); + } + Pair created = createVolume(newVol, _diskOfferingDao.findById(newVol.getDiskOfferingId()), vm, vols, dest); + if (created == null) { + newVol.setPoolId(null); + try { + _volsDao.update(newVol, Event.OperationFailed); + } catch (ConcurrentOperationException e) { + throw new CloudRuntimeException("Unable to update the failure on a volume: " + newVol, e); + } + throw new StorageUnavailableException("Unable to create " + newVol, newVol); + } + newVol.setStatus(AsyncInstanceCreateStatus.Created); + newVol.setFolder(created.second().getPath()); + newVol.setPath(created.first().getPath()); + newVol.setSize(created.first().getSize()); + newVol.setPoolType(created.second().getPoolType()); + newVol.setPodId(created.second().getPodId()); + try { + _volsDao.update(newVol, Event.OperationSucceeded); + } catch (ConcurrentOperationException e) { + throw new CloudRuntimeException("Unable to update an CREATE operation succeeded on volume " + newVol, e); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Volume " + newVol + " is created on " + created.second()); + } + disks[i++] = created.first(); + } + + return disks; + } + + @DB + protected VolumeVO switchVolume(VolumeVO existingVolume) throws StorageUnavailableException { + Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + _volsDao.update(existingVolume, Event.Destroy); + VolumeVO newVolume = allocateDuplicateVolume(existingVolume); + txn.commit(); + return newVolume; + } catch (ConcurrentOperationException e) { + throw new StorageUnavailableException("Unable to duplicate the volume " + existingVolume, existingVolume, e); + } + } + + public Pair createVolume(VolumeVO toBeCreated, DiskOfferingVO offering, VirtualMachineProfile vm, List alreadyCreated, DeployDestination dest) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating volume: " + toBeCreated); + } + DiskProfile diskProfile = new DiskProfile(toBeCreated, offering); + + Set avoids = new HashSet(); + StoragePool pool = null; + while ((pool = findStorage(diskProfile, dest, vm, alreadyCreated, avoids)) != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Trying to create in " + pool); + } + avoids.add(pool); + toBeCreated.setPoolId(pool.getId()); + try { + _volsDao.update(toBeCreated, Volume.Event.OperationRetry); + } catch (ConcurrentOperationException e) { + throw new CloudRuntimeException("Unable to retry a create operation on volume " + toBeCreated); + } + CreateCommand cmd = new CreateCommand(diskProfile, new StorageFilerTO(pool), diskProfile.getSize()); + Answer answer = sendToPool(pool, cmd); + if (answer.getResult()) { + CreateAnswer createAnswer = (CreateAnswer)answer; + return new Pair(createAnswer.getVolume(), pool); + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Unable to create volume " + toBeCreated); + } + return null; + } + @Override public void create(T vm) { List vols = _volsDao.findByInstance(vm.getId()); diff --git a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java index c0d950907b9..bd67360e645 100644 --- a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java @@ -28,6 +28,8 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.HostPodVO; import com.cloud.deploy.DeployDestination; import com.cloud.host.Host; import com.cloud.host.HostVO; @@ -229,8 +231,11 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement } @Override - public StoragePool allocateTo(DiskProfile dskCh, VirtualMachineProfile vm, DeployDestination dest, List disks, Set avoids) { + public StoragePool allocateTo(DiskProfile dskCh, VirtualMachineProfile vm, DeployDestination dest, List disks, Set avoids) { - return null; + VMInstanceVO instance = (VMInstanceVO)(vm.getVm()); + + VMTemplateVO template = vm.getTemplateId() != null ? _templateDao.findById(vm.getTemplateId()) : null; + return allocateToPool(dskCh, (DataCenterVO)dest.getDataCenter(), (HostPodVO)dest.getPod(), dest.getCluster().getId(), instance, template, avoids); } } diff --git a/server/src/com/cloud/storage/allocator/StoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/StoragePoolAllocator.java index deec2ac7049..58bd80d9a07 100644 --- a/server/src/com/cloud/storage/allocator/StoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/StoragePoolAllocator.java @@ -43,5 +43,5 @@ public interface StoragePoolAllocator extends Adapter { String chooseStorageIp(VirtualMachine vm, Host host, Host storage); - StoragePool allocateTo(DiskProfile dskCh, VirtualMachineProfile vm, DeployDestination dest, List disks, Set avoids); + StoragePool allocateTo(DiskProfile dskCh, VirtualMachineProfile vm, DeployDestination dest, List disks, Set avoids); } diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index 9073529922c..11fa385eb02 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -1822,7 +1822,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V if( !_storageMgr.share(secStorageVm, vols, routingHost, false) ) { s_logger.warn("Can not share " + vol.getPath() + " to " + secStorageVm.getName()); - throw new StorageUnavailableException(vol.getPoolId()); + throw new StorageUnavailableException("Can not share " + vol.getPath() + " to " + secStorageVm.getName(), vol); } Answer answer = _agentMgr.easySend(routingHost.getId(), cmd); diff --git a/server/src/com/cloud/vm/MauriceMoss.java b/server/src/com/cloud/vm/MauriceMoss.java index a9764a48403..5163afed108 100644 --- a/server/src/com/cloud/vm/MauriceMoss.java +++ b/server/src/com/cloud/vm/MauriceMoss.java @@ -36,7 +36,9 @@ import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner; import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.StorageUnavailableException; import com.cloud.network.NetworkConfigurationVO; import com.cloud.network.NetworkManager; import com.cloud.offering.ServiceOffering; @@ -233,7 +235,7 @@ public class MauriceMoss implements VmManager { } @Override - public T start(T vm, DeploymentPlan plan) throws InsufficientCapacityException { + public T start(T vm, DeploymentPlan plan) throws InsufficientCapacityException, ConcurrentOperationException { if (s_logger.isDebugEnabled()) { s_logger.debug("Creating actual resources for VM " + vm); } @@ -246,7 +248,7 @@ public class MauriceMoss implements VmManager { Set avoids = new HashSet(); int retry = _retry; - while (retry-- > 0) { + while (retry-- != 0) { // It's != so that it can match -1. DeployDestination dest = null; for (DeploymentPlanner dispatcher : _planners) { dest = dispatcher.plan(vmProfile, plan, avoids); @@ -266,8 +268,15 @@ public class MauriceMoss implements VmManager { _vmDao.updateIf(vm, Event.StartRequested, dest.getHost().getId()); VirtualMachineTO vmTO = new VirtualMachineTO(); + try { + _storageMgr.prepare(vmProfile, dest); + } catch (ConcurrentOperationException e) { + throw e; + } catch (StorageUnavailableException e) { + s_logger.warn("Unable to contact storage.", e); + continue; + } _networkMgr.prepare(vmProfile, dest); -// _storageMgr.prepare(vm, dest); } if (s_logger.isDebugEnabled()) { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 44b834374c2..18312123738 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -179,9 +179,9 @@ import com.cloud.vm.DomainRouter.Role; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.InstanceGroupVMMapDao; import com.cloud.vm.dao.UserVmDao; -import com.cloud.vm.dao.InstanceGroupDao; @Local(value={UserVmManager.class}) public class UserVmManagerImpl implements UserVmManager { @@ -1207,6 +1207,7 @@ public class UserVmManagerImpl implements UserVmManager { } + @Override public void releaseGuestIpAddress(UserVmVO userVm) { ServiceOffering offering = _offeringDao.findById(userVm.getServiceOfferingId()); @@ -2117,7 +2118,7 @@ public class UserVmManagerImpl implements UserVmManager { if( !_storageMgr.share(vm, vols, vmHost, false) ) { s_logger.warn("Can not share " + vm.toString() + " on host " + vmHost.getId()); - throw new StorageUnavailableException(vmHost.getId()); + throw new StorageUnavailableException("Can not share " + vm.toString() + " on host " + vmHost.getId()); } Answer answer = _agentMgr.easySend(vmHost.getId(), cmd); @@ -2400,6 +2401,7 @@ public class UserVmManagerImpl implements UserVmManager { } } + @Override public VMTemplateVO createPrivateTemplateRecord(Long userId, long volumeId, String name, String description, long guestOSId, Boolean requiresHvm, Integer bits, Boolean passwordEnabled, boolean isPublic, boolean featured) throws InvalidParameterValueException { @@ -3014,7 +3016,8 @@ public class UserVmManagerImpl implements UserVmManager { _vmMgr = vmMgr; } - public void run() { + @Override + public void run() { GlobalLock scanLock = GlobalLock.getInternLock("UserVMExpunge"); try { if(scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { diff --git a/utils/src/com/cloud/utils/fsm/FiniteState.java b/utils/src/com/cloud/utils/fsm/FiniteState.java index 7ce9b2a6ed9..ca0d1f668ca 100644 --- a/utils/src/com/cloud/utils/fsm/FiniteState.java +++ b/utils/src/com/cloud/utils/fsm/FiniteState.java @@ -52,4 +52,6 @@ public interface FiniteState { * @return array of events. */ Set getPossibleEvents(); + + String getDescription(); }