diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 523bb6024db..6f919c170a2 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -410,7 +410,8 @@ public class ApiConstants { public static final String EXTERNAL_SWITCH_MGMT_DEVICE_ID = "vsmdeviceid"; public static final String EXTERNAL_SWITCH_MGMT_DEVICE_NAME = "vsmdevicename"; public static final String EXTERNAL_SWITCH_MGMT_DEVICE_STATE = "vsmdevicestate"; - // Would we need to have a capacity field for Cisco N1KV VSM? Max hosts managed by it perhaps? May remove this later. + // Would we need to have a capacity field for Cisco N1KV VSM? Max hosts managed by it perhaps? May remove this +// later. public static final String EXTERNAL_SWITCH_MGMT_DEVICE_CAPACITY = "vsmdevicecapacity"; public static final String CISCO_NEXUS_VSM_NAME = "vsmname"; public static final String VSM_USERNAME = "vsmusername"; @@ -534,6 +535,7 @@ public class ApiConstants { public static final String FOR_DISPLAY = "fordisplay"; public static final String PASSIVE = "passive"; public static final String VERSION = "version"; + public static final String START = "start"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java index 0aafa399d08..f12d15b5f0e 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java @@ -16,8 +16,6 @@ // under the License. package org.apache.cloudstack.api.command.user.vpc; -import org.apache.log4j.Logger; - import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -30,6 +28,7 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; @@ -43,47 +42,54 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd { public static final Logger s_logger = Logger.getLogger(CreateVPCCmd.class.getName()); private static final String s_name = "createvpcresponse"; - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// - @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "the account associated with the VPC. " - + "Must be used with the domainId parameter.") + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "the account associated with the VPC. " + + "Must be used with the domainId parameter.") private String accountName; - @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "the domain ID associated with the VPC. " - + "If used with the account parameter returns the VPC associated with the account for the specified domain.") + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, + description = "the domain ID associated with the VPC. " + + "If used with the account parameter returns the VPC associated with the account for the specified domain.") private Long domainId; - @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "create VPC for the project") + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, + description = "create VPC for the project") private Long projectId; - @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "the ID of the availability zone") + @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, + required = true, description = "the ID of the availability zone") private Long zoneId; @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "the name of the VPC") private String vpcName; - @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "the display text of " + "the VPC") + @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "the display text of " + + "the VPC") private String displayText; - @Parameter(name = ApiConstants.CIDR, type = CommandType.STRING, required = true, description = "the cidr of the VPC. All VPC " - + "guest networks' cidrs should be within this CIDR") + @Parameter(name = ApiConstants.CIDR, type = CommandType.STRING, required = true, description = "the cidr of the VPC. All VPC " + + "guest networks' cidrs should be within this CIDR") private String cidr; - @Parameter(name = ApiConstants.VPC_OFF_ID, - type = CommandType.UUID, - entityType = VpcOfferingResponse.class, - required = true, - description = "the ID of the VPC offering") + @Parameter(name = ApiConstants.VPC_OFF_ID, type = CommandType.UUID, entityType = VpcOfferingResponse.class, + required = true, description = "the ID of the VPC offering") private Long vpcOffering; - @Parameter(name = ApiConstants.NETWORK_DOMAIN, type = CommandType.STRING, description = "VPC network domain. All networks inside the VPC will belong to this domain") + @Parameter(name = ApiConstants.NETWORK_DOMAIN, type = CommandType.STRING, + description = "VPC network domain. All networks inside the VPC will belong to this domain") private String networkDomain; - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// + @Parameter(name = ApiConstants.START, type = CommandType.BOOLEAN, + description = "If set to false, the VPC won't start (VPC VR will not get allocated) until its first network gets implemented. " + + "True by default.", since = "4.3") + private Boolean start; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// public String getAccountName() { return accountName; @@ -117,6 +123,13 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd { return networkDomain; } + public boolean isStart() { + if (start != null) { + return start; + } + return true; + } + @Override public void create() throws ResourceAllocationException { Vpc vpc = _vpcService.createVpc(getZoneId(), getVpcOffering(), getEntityOwnerId(), getVpcName(), getDisplayText(), getCidr(), getNetworkDomain()); @@ -131,10 +144,14 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd { @Override public void execute() { Vpc vpc = null; + boolean success = true; try { - if (_vpcService.startVpc(getEntityId(), true)) { - vpc = _entityMgr.findById(Vpc.class, getEntityId()); + if (isStart()) { + success = _vpcService.startVpc(getEntityId(), true); + } else { + s_logger.debug("Not starting VPC as " + ApiConstants.START + "=false was passed to the API"); } + vpc = _entityMgr.findById(Vpc.class, getEntityId()); } catch (ResourceUnavailableException ex) { s_logger.warn("Exception: ", ex); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); @@ -147,7 +164,7 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd { throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage()); } - if (vpc != null) { + if (vpc != null && success) { VpcResponse response = _responseGenerator.createVpcResponse(vpc); response.setResponseName(getCommandName()); setResponseObject(response); diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 7179944f7ba..75caabe12d3 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -47,6 +47,7 @@ import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.region.PortableIpDao; +import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -147,6 +148,7 @@ import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.StaticNatRuleImpl; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.NetworkACLManager; +import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.dao.PrivateIpDao; import com.cloud.network.vpn.RemoteAccessVpnService; @@ -1031,22 +1033,22 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra (network.getGuestType() == Network.GuestType.Isolated || (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced))) { List ips = null; + Account owner = _entityMgr.findById(Account.class, network.getAccountId()); if (network.getVpcId() != null) { ips = _ipAddressDao.listByAssociatedVpc(network.getVpcId(), true); if (ips.isEmpty()) { - throw new CloudRuntimeException("Vpc is not implemented; there is no source nat ip"); + Vpc vpc = _vpcMgr.getActiveVpc(network.getVpcId()); + s_logger.debug("Creating a source nat ip for vpc " + vpc); + _vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc); } } else { ips = _ipAddressDao.listByAssociatedNetwork(network.getId(), true); - } - - if (ips.isEmpty()) { - s_logger.debug("Creating a source nat ip for network " + network); - Account owner = _entityMgr.findById(Account.class, network.getAccountId()); - _ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, network); + if (ips.isEmpty()) { + s_logger.debug("Creating a source nat ip for network " + network); + _ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, network); + } } } - // get providers to implement List providersToImplement = getNetworkProviders(network.getId()); for (NetworkElement element : _networkElements) {