Boolean displayNetwork = cmd.getDisplayNetwork();
Long aclId = cmd.getAclId();
String isolatedPvlan = cmd.getIsolatedPvlan();
// Validate network offering
NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
if (ntwkOff == null || ntwkOff.isSystemOnly()) {
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering by specified id");
if (ntwkOff != null) {
ex.addProxyObject(ntwkOff.getUuid(), "networkOfferingId");
}
throw ex;
}
// validate physical network and zone
// Check if physical network exists
PhysicalNetwork pNtwk = null;
if (physicalNetworkId != null) {
pNtwk = _physicalNetworkDao.findById(physicalNetworkId);
if (pNtwk == null) {
throw new InvalidParameterValueException("Unable to find a physical network having the specified physical network id");
}
}
if (zoneId == null) {
zoneId = pNtwk.getDataCenterId();
}
if(displayNetwork != null){
if(!_accountMgr.isRootAdmin(caller.getType())){
throw new PermissionDeniedException("Only admin allowed to update displaynetwork parameter");
}
}else{
displayNetwork = true;
}
DataCenter zone = _dcDao.findById(zoneId);
if (zone == null) {
throw new InvalidParameterValueException("Specified zone id was not found");
}
if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) {
// See DataCenterVO.java
PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation since specified Zone is currently disabled");
ex.addProxyObject(zone.getUuid(), "zoneId");
throw ex;
}
// Only domain and account ACL types are supported in Acton.
ACLType aclType = null;
if (aclTypeStr != null) {
if (aclTypeStr.equalsIgnoreCase(ACLType.Account.toString())) {
aclType = ACLType.Account;
} else if (aclTypeStr.equalsIgnoreCase(ACLType.Domain.toString())) {
aclType = ACLType.Domain;
} else {
throw new InvalidParameterValueException("Incorrect aclType specified. Check the API documentation for supported types");
}
// In 3.0 all Shared networks should have aclType == Domain, all Isolated networks aclType==Account
if (ntwkOff.getGuestType() == GuestType.Isolated) {
if (aclType != ACLType.Account) {
throw new InvalidParameterValueException("AclType should be " + ACLType.Account + " for network of type " + Network.GuestType.Isolated);
}
} else if (ntwkOff.getGuestType() == GuestType.Shared) {
if (!(aclType == ACLType.Domain || aclType == ACLType.Account)) {
throw new InvalidParameterValueException("AclType should be " + ACLType.Domain + " or " +
ACLType.Account + " for network of type " + Network.GuestType.Shared);
}
}
} else {
if (ntwkOff.getGuestType() == GuestType.Isolated) {
aclType = ACLType.Account;
} else if (ntwkOff.getGuestType() == GuestType.Shared) {
aclType = ACLType.Domain;
}
}
// Only Admin can create Shared networks
if (ntwkOff.getGuestType() == GuestType.Shared && !_accountMgr.isAdmin(caller.getType())) {
throw new InvalidParameterValueException("Only Admins can create network with guest type " + GuestType.Shared);
}
// Check if the network is domain specific
if (aclType == ACLType.Domain) {
// only Admin can create domain with aclType=Domain
if (!_accountMgr.isAdmin(caller.getType())) {
throw new PermissionDeniedException("Only admin can create networks with aclType=Domain");
}
// only shared networks can be Domain specific
if (ntwkOff.getGuestType() != GuestType.Shared) {
throw new InvalidParameterValueException("Only " + GuestType.Shared + " networks can have aclType=" + ACLType.Domain);
}
if (domainId != null) {
if (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Shared) {
throw new InvalidParameterValueException("Domain level networks are supported just for traffic type "
+ TrafficType.Guest + " and guest type " + Network.GuestType.Shared);
}
DomainVO domain = _domainDao.findById(domainId);
if (domain == null) {
throw new InvalidParameterValueException("Unable to find domain by specified id");
}
_accountMgr.checkAccess(caller, domain);
}
isDomainSpecific = true;
} else if (subdomainAccess != null) {
throw new InvalidParameterValueException("Parameter subDomainAccess can be specified only with aclType=Domain");
}
Account owner = null;
if ((cmd.getAccountName() != null && domainId != null) || cmd.getProjectId() != null) {
owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), domainId, cmd.getProjectId());
} else {
owner = caller;
}
UserContext.current().setAccountId(owner.getAccountId());
boolean ipv4 = true, ipv6 = false;
if (startIP != null) {
ipv4 = true;
}
if (startIPv6 != null) {
ipv6 = true;
}
if (gateway != null) {
try {
// getByName on a literal representation will only check validity of the address
// http://docs.oracle.com/javase/6/docs/api/java/net/InetAddress.html#getByName(java.lang.String)
InetAddress gatewayAddress = InetAddress.getByName(gateway);
if (gatewayAddress instanceof Inet6Address) {
ipv6 = true;
} else {
ipv4 = true;
}
}
catch (UnknownHostException e) {
s_logger.error("Unable to convert gateway IP to a InetAddress", e);
throw new InvalidParameterValueException("Gateway parameter is invalid");
}
}
String cidr = null;
if (ipv4) {
// if end ip is not specified, default it to startIp
if (startIP != null) {
if (!NetUtils.isValidIp(startIP)) {
throw new InvalidParameterValueException("Invalid format for the startIp parameter");
}
if (endIP == null) {
endIP = startIP;
} else if (!NetUtils.isValidIp(endIP)) {
throw new InvalidParameterValueException("Invalid format for the endIp parameter");
}
}
if (startIP != null && endIP != null) {
if (!(gateway != null && netmask != null)) {
throw new InvalidParameterValueException("gateway and netmask should be defined when startIP/endIP are passed in");
}
}
if (gateway != null && netmask != null) {
if (!NetUtils.isValidIp(gateway)) {
throw new InvalidParameterValueException("Invalid gateway");
}
if (!NetUtils.isValidNetmask(netmask)) {
throw new InvalidParameterValueException("Invalid netmask");
}
cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
}
}
if (ipv6) {
if (endIPv6 == null) {
endIPv6 = startIPv6;
}
_networkModel.checkIp6Parameters(startIPv6, endIPv6, ip6Gateway, ip6Cidr);
if (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() != Network.GuestType.Shared) {
throw new InvalidParameterValueException("Can only support create IPv6 network with advance shared network!");
}
}
if (isolatedPvlan != null && (zone.getNetworkType() != NetworkType.Advanced || ntwkOff.getGuestType() != Network.GuestType.Shared)) {
throw new InvalidParameterValueException("Can only support create Private VLAN network with advance shared network!");
}
if (isolatedPvlan != null && ipv6) {
throw new InvalidParameterValueException("Can only support create Private VLAN network with IPv4!");
}
// Regular user can create Guest Isolated Source Nat enabled network only
if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL
&& (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Isolated
&& areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))) {
throw new InvalidParameterValueException("Regular user can create a network only from the network" +
" offering having traffic type " + TrafficType.Guest + " and network type "
+ Network.GuestType.Isolated + " with a service " + Service.SourceNat.getName() + " enabled");
}
// Don't allow to specify vlan if the caller is not ROOT admin
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && (ntwkOff.getSpecifyVlan() || vlanId != null)) {
throw new InvalidParameterValueException("Only ROOT admin is allowed to specify vlanId");
}
if (ipv4) {
// For non-root admins check cidr limit - if it's allowed by global config value
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && cidr != null) {
String[] cidrPair = cidr.split("\\/");
int cidrSize = Integer.valueOf(cidrPair[1]);
if (cidrSize < _cidrLimit) {
throw new InvalidParameterValueException("Cidr size can't be less than " + _cidrLimit);
}
}
}
Collection<String> ntwkProviders = _networkMgr.finalizeServicesAndProvidersForNetwork(ntwkOff, physicalNetworkId).values();
if (ipv6 && providersConfiguredForExternalNetworking(ntwkProviders)) {
throw new InvalidParameterValueException("Cannot support IPv6 on network offering with external devices!");
}
if (isolatedPvlan != null && providersConfiguredForExternalNetworking(ntwkProviders)) {
throw new InvalidParameterValueException("Cannot support private vlan on network offering with external devices!");
}
if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) {
if (ntwkOff.getGuestType() == GuestType.Shared && (zone.getNetworkType() == NetworkType.Advanced) &&
isSharedNetworkOfferingWithServices(networkOfferingId)) {
// validate if CIDR specified overlaps with any of the CIDR's allocated for isolated networks and shared networks in the zone
checkSharedNetworkCidrOverlap(zoneId, pNtwk.getId(), cidr);
} else {
// if the guest network is for the VPC, if any External Provider are supported in VPC
// cidr will not be null as it is generated from the super cidr of vpc.
// if cidr is not null and network is not part of vpc then throw the exception
if (vpcId == null)
throw new InvalidParameterValueException("Cannot specify CIDR when using network offering with external devices!");
}
}
// Vlan is created in 1 cases - works in Advance zone only:
// 1) GuestType is Shared
boolean createVlan = (startIP != null && endIP != null && zone.getNetworkType() == NetworkType.Advanced
&& (ntwkOff.getGuestType() == Network.GuestType.Shared));
if (!createVlan) {
// Only support advance shared network in IPv6, which means createVlan is a must
if (ipv6) {
createVlan = true;
}
}
// Can add vlan range only to the network which allows it
if (createVlan && !ntwkOff.getSpecifyIpRanges()) {
InvalidParameterValueException ex = new InvalidParameterValueException("Network offering with specified id doesn't support adding multiple ip ranges");
ex.addProxyObject(ntwkOff.getUuid(), "networkOfferingId");
throw ex;
}
Transaction txn = Transaction.currentTxn();
txn.start();
Long sharedDomainId = null;
if (isDomainSpecific) {
if (domainId != null) {
sharedDomainId = domainId;
} else {
sharedDomainId = _domainMgr.getDomain(Domain.ROOT_DOMAIN).getId();
subdomainAccess = true;
}
}
// default owner to system if network has aclType=Domain
if (aclType == ACLType.Domain) {
owner = _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM);
}
//Create guest network
Network network = null;
if (vpcId != null) {
if (!_configMgr.isOfferingForVpc(ntwkOff)){
throw new InvalidParameterValueException("Network offering can't be used for VPC networks");
}
if(aclId != null){
NetworkACL acl = _networkACLDao.findById(aclId);
if(acl == null){
throw new InvalidParameterValueException("Unable to find specified NetworkACL");
}
if(aclId != NetworkACL.DEFAULT_DENY && aclId != NetworkACL.DEFAULT_ALLOW) {
//ACL is not default DENY/ALLOW
// ACL should be associated with a VPC
if(!vpcId.equals(acl.getVpcId())){
throw new InvalidParameterValueException("ACL: "+aclId+" do not belong to the VPC");
}
}
}
network = _vpcMgr.createVpcGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId,
networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, aclId, caller, displayNetwork);
} else {
if (_configMgr.isOfferingForVpc(ntwkOff)){
throw new InvalidParameterValueException("Network offering can be used for VPC networks only");
}
if (ntwkOff.getInternalLb()) {
throw new InvalidParameterValueException("Internal Lb can be enabled on vpc networks only");
}
network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId,
networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId,
ip6Gateway, ip6Cidr, displayNetwork, isolatedPvlan);
}
if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN && createVlan) {
// Create vlan ip range
_configMgr.createVlanAndPublicIpRange(pNtwk.getDataCenterId(), network.getId(), physicalNetworkId,
false, null, startIP, endIP, gateway, netmask, vlanId, null, startIPv6, endIPv6, ip6Gateway, ip6Cidr);
}
txn.commit();
// if the network offering has persistent set to true, implement the network
if ( ntwkOff.getIsPersistent() ) {
try {
if ( network.getState() == Network.State.Setup ) {
s_logger.debug("Network id=" + network.getId() + " is already provisioned");
return network;
}