1) Added VPC restart support - new api command RestartVPC. The purpose of the call is to shutdown and start VPC including VPCVirtualRouter restart, rules re-implement, etc

2) Only networks created from offerings with conserveMode=false, can participate in VPC
This commit is contained in:
Alena Prokharchyk 2012-05-25 15:34:51 -07:00
parent fbdf10bac7
commit d3b1925e55
17 changed files with 228 additions and 39 deletions

View File

@ -124,7 +124,9 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd{
//TODO - prepare vpc here (call start() method, it should start the VR, associate source nat ip address, etc)
Vpc vpc = null;
try {
vpc = _vpcService.startVpc(this.getEntityId());
if (_vpcService.startVpc(this.getEntityId())) {
vpc = _vpcService.getVpc(getEntityId());
}
} catch (ResourceUnavailableException ex) {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(BaseCmd.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
@ -136,6 +138,7 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd{
s_logger.trace(ex);
throw new ServerApiException(BaseCmd.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage());
}
if (vpc != null) {
VpcResponse response = _responseGenerator.createVpcResponse(vpc);
response.setResponseName(getCommandName());

View File

@ -83,10 +83,6 @@ public class DeleteVPCCmd extends BaseAsyncCmd{
} catch (ConcurrentOperationException ex) {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, ex.getMessage());
} catch (InsufficientCapacityException ex) {
s_logger.info(ex);
s_logger.trace(ex);
throw new ServerApiException(BaseCmd.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage());
}
}

View File

@ -62,7 +62,7 @@ public class ListNetworksCmd extends BaseListProjectAndAccountResourcesCmd {
@Parameter(name=ApiConstants.SUPPORTED_SERVICES, type=CommandType.LIST, collectionType=CommandType.STRING, description="list network offerings supporting certain services")
private List<String> supportedServices;
@Parameter(name=ApiConstants.RESTART_REQUIRED, type=CommandType.BOOLEAN, description="list network offerings by restartRequired option")
@Parameter(name=ApiConstants.RESTART_REQUIRED, type=CommandType.BOOLEAN, description="list networks by restartRequired")
private Boolean restartRequired;
@Parameter(name=ApiConstants.SPECIFY_IP_RANGES, type=CommandType.BOOLEAN, description="true if need to list only networks which support specifying ip ranges")

View File

@ -24,7 +24,6 @@ import com.cloud.api.Parameter;
import com.cloud.api.response.ListResponse;
import com.cloud.api.response.VpcResponse;
import com.cloud.network.vpc.Vpc;
import com.cloud.network.vpc.Vpc;
/**
* @author Alena Prokharchyk
@ -75,6 +74,9 @@ public class ListVPCsCmd extends BaseListAccountResourcesCmd{
@Parameter(name=ApiConstants.STATE, type=CommandType.STRING, description="list VPCs by state")
private String state;
@Parameter(name=ApiConstants.RESTART_REQUIRED, type=CommandType.BOOLEAN, description="list VPCs by restartRequired option")
private Boolean restartRequired;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -119,6 +121,10 @@ public class ListVPCsCmd extends BaseListAccountResourcesCmd{
return state;
}
public Boolean getRestartRequired() {
return restartRequired;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@ -127,7 +133,8 @@ public class ListVPCsCmd extends BaseListAccountResourcesCmd{
public void execute() {
List<? extends Vpc> vpcs = _vpcService.listVpcs(getId(), getVpcName(), getDisplayText(),
getSupportedServices(), getCidr(), getVpcOffId(), getState(), getAccountName(), getDomainId(),
this.getKeyword(), this.getStartIndex(), this.getPageSizeVal(), getZoneId(), this.isRecursive(), this.listAll());
this.getKeyword(), this.getStartIndex(), this.getPageSizeVal(), getZoneId(), this.isRecursive(),
this.listAll(), getRestartRequired());
ListResponse<VpcResponse> response = new ListResponse<VpcResponse>();
List<VpcResponse> offeringResponses = new ArrayList<VpcResponse>();
for (Vpc vpc : vpcs) {

View File

@ -0,0 +1,95 @@
// Copyright 2012 Citrix Systems, Inc. Licensed under the
package com.cloud.api.commands;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseAsyncCmd;
import com.cloud.api.BaseCmd;
import com.cloud.api.IdentityMapper;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.response.SuccessResponse;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.vpc.Vpc;
import com.cloud.user.Account;
/**
* @author Alena Prokharchyk
*/
public class RestartVPCCmd extends BaseAsyncCmd{
public static final Logger s_logger = Logger.getLogger(RestartVPCCmd.class.getName());
private static final String _name = "restartvpcresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@IdentityMapper(entityTableName="vpc")
@Parameter(name=ApiConstants.ID, type=CommandType.LONG, description="the id of the VPC")
private Long id;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getId() {
return id;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return _name;
}
@Override
public long getEntityOwnerId() {
Vpc vpc = _entityMgr.findById(Vpc.class, getId());
if (vpc != null) {
return vpc.getAccountId();
}
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
@Override
public void execute(){
try {
boolean result = _vpcService.restartVpc(getId());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to restart VPC");
}
} catch (ResourceUnavailableException ex) {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(BaseCmd.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
} catch (ConcurrentOperationException ex) {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, ex.getMessage());
} catch (InsufficientCapacityException ex) {
s_logger.info(ex);
s_logger.trace(ex);
throw new ServerApiException(BaseCmd.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage());
}
}
@Override
public String getEventType() {
return EventTypes.EVENT_VPC_RESTART;
}
@Override
public String getEventDescription() {
return "restarting VPC id=" + getId();
}
}

View File

@ -101,6 +101,6 @@ public class UpdateVPCCmd extends BaseAsyncCmd{
@Override
public String getEventDescription() {
return "Updating VPC id=" + getId();
return "updating VPC id=" + getId();
}
}

View File

@ -71,6 +71,11 @@ public class VpcResponse extends BaseResponse implements ControlledEntityRespons
@SerializedName(ApiConstants.NETWORK) @Param(description="the list of networks belongign to the VPC", responseObject = NetworkResponse.class)
private List<NetworkResponse> networks;
@SerializedName(ApiConstants.RESTART_REQUIRED) @Param(description="true network requires restart")
private Boolean restartRequired;
@SerializedName(ApiConstants.NETWORK_DOMAIN) @Param(description="the network domain")
private String networkDomain;
public void setId(Long id) {
this.id.setValue(id);
@ -140,4 +145,12 @@ public class VpcResponse extends BaseResponse implements ControlledEntityRespons
public void setNetworks(List<NetworkResponse> networks) {
this.networks = networks;
}
public void setRestartRequired(Boolean restartRequired) {
this.restartRequired = restartRequired;
}
public void setNetworkDomain(String networkDomain) {
this.networkDomain = networkDomain;
}
}

View File

@ -257,6 +257,7 @@ public class EventTypes {
public static final String EVENT_VPC_CREATE = "VPC.CREATE";
public static final String EVENT_VPC_UPDATE = "VPC.UPDATE";
public static final String EVENT_VPC_DELETE = "VPC.DELETE";
public static final String EVENT_VPC_RESTART = "VPC.RESTART";
public static final String EVENT_VPC_OFFERING_CREATE = "VPC.OFFERING.CREATE";

View File

@ -45,9 +45,8 @@ public interface Vpc extends ControlledEntity{
String getDisplayText();
/**
* @return
*/
String getNetworkDomain();
String getNetworkDomain();
boolean isRestartRequired();
}

View File

@ -77,7 +77,7 @@ public interface VpcService {
* @throws ResourceUnavailableException
* @throws ConcurrentOperationException
*/
public boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
public boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException;
/**
* @param vpcId
@ -102,12 +102,14 @@ public interface VpcService {
* @param zoneId TODO
* @param isRecursive TODO
* @param listAll TODO
* @param restartRequired TODO
* @param vpc
* @return
*/
public List<? extends Vpc> listVpcs(Long id, String vpcName, String displayText,
List<String> supportedServicesStr, String cidr, Long vpcOffId, String state, String accountName, Long domainId,
String keyword, Long startIndex, Long pageSizeVal, Long zoneId, Boolean isRecursive, Boolean listAll);
String keyword, Long startIndex, Long pageSizeVal, Long zoneId, Boolean isRecursive, Boolean listAll,
Boolean restartRequired);
/**
* @param vpcId
@ -116,15 +118,21 @@ public interface VpcService {
* @throws ResourceUnavailableException
* @throws ConcurrentOperationException
*/
Vpc startVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
boolean startVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
/**
* @param vpcId
* @return
* @throws ConcurrentOperationException
* @throws ResourceUnavailableException
* @throws InsufficientCapacityException
*/
Vpc shutdownVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
boolean shutdownVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException;
/**
* @param id
* @return
* @throws InsufficientCapacityException
*/
boolean restartVpc(Long id) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
}

View File

@ -339,7 +339,7 @@ createVPC=com.cloud.api.commands.CreateVPCCmd;15
listVPCs=com.cloud.api.commands.ListVPCsCmd;15
deleteVPC=com.cloud.api.commands.DeleteVPCCmd;15
updateVPC=com.cloud.api.commands.UpdateVPCCmd;15
restartVPC=com.cloud.api.commands.RestartVPCCmd;15
#### VPC offering commands
createVPCOffering=com.cloud.api.commands.CreateVPCOfferingCmd;1

View File

@ -3449,6 +3449,8 @@ public class ApiResponseHelper implements ResponseGenerator {
response.setVpcOfferingId(vpc.getVpcOfferingId());
response.setCidr(vpc.getCidr());
response.setZoneId(vpc.getZoneId());
response.setRestartRequired(vpc.isRestartRequired());
response.setNetworkDomain(vpc.getNetworkDomain());
Map<Service, Set<Provider>> serviceProviderMap = ApiDBUtils.listVpcOffServices(vpc.getVpcOfferingId());
List<ServiceResponse> serviceResponses = new ArrayList<ServiceResponse>();

View File

@ -17,7 +17,6 @@ import java.util.Map;
import java.util.Set;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
@ -88,7 +87,6 @@ public interface VpcManager extends VpcService{
* @return
* @throws ConcurrentOperationException
* @throws ResourceUnavailableException
* @throws InsufficientCapacityException
*/
boolean destroyVpc(Vpc vpc) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
boolean destroyVpc(Vpc vpc) throws ConcurrentOperationException, ResourceUnavailableException;
}

View File

@ -64,7 +64,6 @@ import com.cloud.utils.db.Filter;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.ReservationContextImpl;
@ -482,7 +481,7 @@ public class VpcManagerImpl implements VpcManager, Manager{
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_DELETE, eventDescription = "deleting VPC")
public boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
public boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException {
UserContext.current().setEventDetails(" Id: " + vpcId);
Account caller = UserContext.current().getCaller();
@ -494,13 +493,12 @@ public class VpcManagerImpl implements VpcManager, Manager{
//verify permissions
_accountMgr.checkAccess(caller, null, false, vpc);
return destroyVpc(vpc);
}
@Override
public boolean destroyVpc(Vpc vpc) throws ConcurrentOperationException, ResourceUnavailableException,
InsufficientCapacityException {
public boolean destroyVpc(Vpc vpc) throws ConcurrentOperationException, ResourceUnavailableException {
UserContext ctx = UserContext.current();
//don't allow to delete vpc if it's in use by existing networks
@ -516,7 +514,10 @@ public class VpcManagerImpl implements VpcManager, Manager{
_vpcDao.update(vpc.getId(), vpcVO);
//shutdown VPC
shutdownVpc(vpc.getId());
if (!shutdownVpc(vpc.getId())) {
s_logger.warn("Failed to shutdown vpc " + vpc + " as a part of vpc destroy process");
return false;
}
//cleanup vpc resources
if (!cleanupVpcResources(vpc.getId(), ctx.getCaller(), ctx.getCallerUserId())) {
@ -535,12 +536,15 @@ public class VpcManagerImpl implements VpcManager, Manager{
@ActionEvent(eventType = EventTypes.EVENT_VPC_UPDATE, eventDescription = "updating vpc")
public Vpc updateVpc(long vpcId, String vpcName, String displayText) {
UserContext.current().setEventDetails(" Id: " + vpcId);
Account caller = UserContext.current().getCaller();
// Verify input parameters
VpcVO vpcToUpdate = _vpcDao.findById(vpcId);
if (vpcToUpdate == null) {
throw new InvalidParameterValueException("Unable to find vpc offering " + vpcId);
}
_accountMgr.checkAccess(caller, null, false, vpcToUpdate);
VpcVO vpc = _vpcDao.createForUpdate(vpcId);
@ -564,7 +568,7 @@ public class VpcManagerImpl implements VpcManager, Manager{
@Override
public List<? extends Vpc> listVpcs(Long id, String vpcName, String displayText, List<String> supportedServicesStr,
String cidr, Long vpcOffId, String state, String accountName, Long domainId, String keyword,
Long startIndex, Long pageSizeVal, Long zoneId, Boolean isRecursive, Boolean listAll) {
Long startIndex, Long pageSizeVal, Long zoneId, Boolean isRecursive, Boolean listAll, Boolean restartRequired) {
Account caller = UserContext.current().getCaller();
List<Long> permittedAccounts = new ArrayList<Long>();
@ -586,6 +590,7 @@ public class VpcManagerImpl implements VpcManager, Manager{
sb.and("vpcOfferingId", sb.entity().getVpcOfferingId(), SearchCriteria.Op.EQ);
sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.EQ);
sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ);
sb.and("restartRequired", sb.entity().isRestartRequired(), SearchCriteria.Op.EQ);
// now set the SC criteria...
@ -622,6 +627,10 @@ public class VpcManagerImpl implements VpcManager, Manager{
if (state != null) {
sc.addAnd("state", SearchCriteria.Op.EQ, state);
}
if (restartRequired != null) {
sc.addAnd("restartRequired", SearchCriteria.Op.EQ, restartRequired);
}
List<VpcVO> vpcs = _vpcDao.search(sc, searchFilter);
@ -675,7 +684,7 @@ public class VpcManagerImpl implements VpcManager, Manager{
}
@Override
public Vpc startVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException,
public boolean startVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException,
InsufficientCapacityException {
UserContext ctx = UserContext.current();
Account caller = ctx.getCaller();
@ -699,17 +708,17 @@ public class VpcManagerImpl implements VpcManager, Manager{
//deploy provider
if (getVpcElement().implementVpc(vpc, dest, context)) {
s_logger.debug("Vpc " + vpc + " has started succesfully");
return getVpc(vpc.getId());
return true;
} else {
throw new CloudRuntimeException("Failed to start vpc " + vpc);
s_logger.warn("Vpc " + vpc + " failed to start");
//FIXME - add cleanup logic here
return false;
}
}
@Override
public Vpc shutdownVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException,
InsufficientCapacityException {
public boolean shutdownVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException {
UserContext ctx = UserContext.current();
Account caller = ctx.getCaller();
@ -726,13 +735,12 @@ public class VpcManagerImpl implements VpcManager, Manager{
boolean success = getVpcElement().shutdownVpc(vpc);
//FIXME - once more features are added to vpc (gateway/firewall rules, etc - cleanup them here)
if (success) {
s_logger.debug("Vpc " + vpc + " has been stopped succesfully");
return getVpc(vpc.getId());
s_logger.debug("Vpc " + vpc + " has been shutdown succesfully");
} else {
throw new CloudRuntimeException("Failed to stop vpc " + vpc);
s_logger.warn("Vpc " + vpc + " failed to shutdown");
}
return success;
}
@Override
@ -794,6 +802,12 @@ public class VpcManagerImpl implements VpcManager, Manager{
if (guestNtwkOff.getRedundantRouter()) {
throw new InvalidParameterValueException("No redunant router support when network belnogs to VPC");
}
//8) Conserve mode should be off
if (guestNtwkOff.isConserveMode()) {
throw new InvalidParameterValueException("Only networks with conserve mode Off can belong to VPC");
}
} finally {
s_logger.debug("Releasing lock for " + locked);
_vpcDao.releaseFromLockTable(locked.getId());
@ -830,4 +844,44 @@ public class VpcManagerImpl implements VpcManager, Manager{
return success;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_RESTART, eventDescription = "restarting vpc")
public boolean restartVpc(Long vpcId) throws ConcurrentOperationException, ResourceUnavailableException,
InsufficientCapacityException {
Account caller = UserContext.current().getCaller();
// Verify input parameters
VpcVO vpc = _vpcDao.findById(vpcId);
if (vpc == null) {
throw new InvalidParameterValueException("Unable to find vpc offering " + vpcId);
}
_accountMgr.checkAccess(caller, null, false, vpc);
s_logger.debug("Restarting VPC " + vpc);
boolean restartRequired = false;
try {
s_logger.debug("Shuttign down VPC " + vpc + " as a part of VPC restart process");
if (!shutdownVpc(vpcId)) {
s_logger.warn("Failed to shutdown vpc as a part of VPC " + vpc + " restart process");
restartRequired = true;
return false;
}
s_logger.debug("Starting VPC " + vpc + " as a part of VPC restart process");
if (!startVpc(vpcId)) {
s_logger.warn("Failed to start vpc as a part of VPC " + vpc + " restart process");
restartRequired = true;
return false;
}
s_logger.debug("VPC " + vpc + " was restarted successfully");
return true;
} finally {
s_logger.debug("Updating VPC " + vpc + " with restartRequired=" + restartRequired);
vpc.setRestartRequired(restartRequired);
_vpcDao.update(vpc.getId(), vpc);
}
}
}

View File

@ -73,6 +73,9 @@ public class VpcVO implements Vpc, Identity {
@Column(name="network_domain")
String networkDomain;
@Column(name="restart_required")
boolean restartRequired = false;
public VpcVO() {
this.uuid = UUID.randomUUID().toString();
}
@ -172,4 +175,13 @@ public class VpcVO implements Vpc, Identity {
public String getNetworkDomain() {
return networkDomain;
}
public void setRestartRequired(boolean restartRequired) {
this.restartRequired = restartRequired;
}
@Override
public boolean isRestartRequired() {
return restartRequired;
}
}

View File

@ -2144,6 +2144,7 @@ CREATE TABLE `cloud`.`vpc` (
`network_domain` varchar(255) COMMENT 'network domain',
`removed` datetime COMMENT 'date removed if not null',
`created` datetime NOT NULL COMMENT 'date created',
`restart_required` int(1) unsigned NOT NULL DEFAULT 0 COMMENT '1 if restart is required for the VPC',
PRIMARY KEY (`id`),
INDEX `i_vpc__removed`(`removed`),
CONSTRAINT `fk_vpc__zone_id` FOREIGN KEY `fk_vpc__zone_id` (`zone_id`) REFERENCES `data_center` (`id`) ON DELETE CASCADE,

View File

@ -3,7 +3,7 @@
# the following two variables are used by the target "waf dist"
# if you change 'em here, you need to change it also in cloud.spec, add a %changelog entry there, and add an entry in debian/changelog
VERSION = '3.0.3.2012-05-25T21:12:57Z'
VERSION = '3.0.3.2012-05-25T22:13:38Z'
APPNAME = 'cloud'
import shutil,os