[ 
https://issues.apache.org/jira/browse/CLOUDSTACK-10102?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16298327#comment-16298327
 ] 

ASF GitHub Bot commented on CLOUDSTACK-10102:
---------------------------------------------

rhtyd closed pull request #2281: CLOUDSTACK-10102: New network type (L2)
URL: https://github.com/apache/cloudstack/pull/2281
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/api/src/com/cloud/network/Network.java 
b/api/src/com/cloud/network/Network.java
index a02c8cfdbe2..95833d86b63 100644
--- a/api/src/com/cloud/network/Network.java
+++ b/api/src/com/cloud/network/Network.java
@@ -38,7 +38,7 @@
 public interface Network extends ControlledEntity, StateObject<Network.State>, 
InternalIdentity, Identity, Serializable, Displayable {
 
     public enum GuestType {
-        Shared, Isolated
+        Shared, Isolated, L2
     }
 
     public String updatingInSequence ="updatingInSequence";
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 1ddff84f991..2d30cedcb8d 100644
--- 
a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ 
b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -2207,8 +2207,8 @@ public Network createGuestNetwork(final long 
networkOfferingId, final String nam
                         + zone.getName());
             }
             if (! UuidUtils.validateUUID(vlanId)){
-                // For Isolated networks, don't allow to create network with 
vlan that already exists in the zone
-                if (ntwkOff.getGuestType() == GuestType.Isolated) {
+                // For Isolated and L2 networks, don't allow to create network 
with vlan that already exists in the zone
+                if (ntwkOff.getGuestType() == GuestType.Isolated || 
ntwkOff.getGuestType() == GuestType.L2) {
                     if (_networksDao.listByZoneAndUriAndGuestType(zoneId, 
uri.toString(), null).size() > 0) {
                         throw new InvalidParameterValueException("Network with 
vlan " + vlanId + " already exists or overlaps with other network vlans in zone 
" + zoneId);
                     } else {
@@ -2289,8 +2289,9 @@ public Network createGuestNetwork(final long 
networkOfferingId, final String nam
         // with different Cidrs for the same Shared network
         final boolean cidrRequired = zone.getNetworkType() == 
NetworkType.Advanced
                 && ntwkOff.getTrafficType() == TrafficType.Guest
-                && (ntwkOff.getGuestType() == GuestType.Shared || 
ntwkOff.getGuestType() == GuestType.Isolated && 
!_networkModel.areServicesSupportedByNetworkOffering(
-                        ntwkOff.getId(), Service.SourceNat));
+                && (ntwkOff.getGuestType() == GuestType.Shared || 
(ntwkOff.getGuestType() == GuestType.Isolated
+                && 
!_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), 
Service.SourceNat))
+                || ntwkOff.getGuestType() == GuestType.L2 && 
!_networkModel.listNetworkOfferingServices(ntwkOff.getId()).isEmpty());
         if (cidr == null && ip6Cidr == null && cidrRequired) {
             throw new 
InvalidParameterValueException("StartIp/endIp/gateway/netmask are required when 
create network of" + " type " + Network.GuestType.Shared
                     + " and network of type " + GuestType.Isolated + " with 
service " + Service.SourceNat.getName() + " disabled");
@@ -2560,7 +2561,6 @@ public boolean destroyNetwork(final long networkId, final 
ReservationContext con
             s_logger.debug("Unable to find network with id: " + networkId);
             return false;
         }
-
         // Make sure that there are no user vms in the network that are not 
Expunged/Error
         final List<UserVmVO> userVms = 
_userVmDao.listByNetworkIdAndStates(networkId);
 
diff --git a/engine/schema/src/com/cloud/vm/dao/UserVmDaoImpl.java 
b/engine/schema/src/com/cloud/vm/dao/UserVmDaoImpl.java
index b1ff7060ba1..d13234d1016 100644
--- a/engine/schema/src/com/cloud/vm/dao/UserVmDaoImpl.java
+++ b/engine/schema/src/com/cloud/vm/dao/UserVmDaoImpl.java
@@ -29,6 +29,9 @@
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 
+import com.cloud.network.Network;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkVO;
 import org.apache.log4j.Logger;
 
 import com.cloud.server.ResourceTag.ResourceObjectType;
@@ -77,6 +80,8 @@
     // ResourceTagsDaoImpl _tagsDao = 
ComponentLocator.inject(ResourceTagsDaoImpl.class);
     @Inject
     ResourceTagDao _tagsDao;
+    @Inject
+    NetworkDao networkDao;
 
     private static final String LIST_PODS_HAVING_VMS_FOR_ACCOUNT =
             "SELECT pod_id FROM cloud.vm_instance WHERE data_center_id = ? AND 
account_id = ? AND pod_id IS NOT NULL AND (state = 'Running' OR state = 
'Stopped') "
@@ -299,21 +304,32 @@ public void updateVM(long id, String displayName, boolean 
enable, Long osTypeId,
         return listBy(sc);
     }
 
-    @Override
-    public List<UserVmVO> listByNetworkIdAndStates(long networkId, State... 
states) {
-        if (UserVmSearch == null) {
+    /**
+     * Recreates UserVmSearch depending on network type, as nics on L2 
networks have no ip addresses
+     * @param network network
+     */
+    private void recreateUserVmSeach(NetworkVO network) {
+        if (network != null) {
             SearchBuilder<NicVO> nicSearch = _nicDao.createSearchBuilder();
             nicSearch.and("networkId", nicSearch.entity().getNetworkId(), 
SearchCriteria.Op.EQ);
             nicSearch.and("removed", nicSearch.entity().getRemoved(), 
SearchCriteria.Op.NULL);
-            nicSearch.and().op("ip4Address", 
nicSearch.entity().getIPv4Address(), SearchCriteria.Op.NNULL);
-            nicSearch.or("ip6Address", nicSearch.entity().getIPv6Address(), 
SearchCriteria.Op.NNULL);
-            nicSearch.cp();
+            if (!Network.GuestType.L2.equals(network.getGuestType())) {
+                nicSearch.and().op("ip4Address", 
nicSearch.entity().getIPv4Address(), SearchCriteria.Op.NNULL);
+                nicSearch.or("ip6Address", 
nicSearch.entity().getIPv6Address(), SearchCriteria.Op.NNULL);
+                nicSearch.cp();
+            }
 
             UserVmSearch = createSearchBuilder();
             UserVmSearch.and("states", UserVmSearch.entity().getState(), 
SearchCriteria.Op.IN);
             UserVmSearch.join("nicSearch", nicSearch, 
UserVmSearch.entity().getId(), nicSearch.entity().getInstanceId(), 
JoinBuilder.JoinType.INNER);
             UserVmSearch.done();
         }
+    }
+
+    @Override
+    public List<UserVmVO> listByNetworkIdAndStates(long networkId, State... 
states) {
+        NetworkVO network = networkDao.findById(networkId);
+        recreateUserVmSeach(network);
 
         SearchCriteria<UserVmVO> sc = UserVmSearch.create();
         if (states != null && states.length != 0) {
diff --git 
a/plugins/network-elements/brocade-vcs/test/com/cloud/network/guru/BrocadeVcsGuestNetworkGuruTest.java
 
b/plugins/network-elements/brocade-vcs/test/com/cloud/network/guru/BrocadeVcsGuestNetworkGuruTest.java
index bf30bd01fcd..b73ddabae19 100644
--- 
a/plugins/network-elements/brocade-vcs/test/com/cloud/network/guru/BrocadeVcsGuestNetworkGuruTest.java
+++ 
b/plugins/network-elements/brocade-vcs/test/com/cloud/network/guru/BrocadeVcsGuestNetworkGuruTest.java
@@ -107,6 +107,7 @@ public void setUp() {
         guru._ntwkOfferingSrvcDao = nosd;
         guru._dcDao = dcdao;
         guru._agentMgr = agentmgr;
+        ((GuestNetworkGuru)guru)._networkModel = netmodel;
 
         final DataCenterVO dc = mock(DataCenterVO.class);
         when(dc.getNetworkType()).thenReturn(NetworkType.Advanced);
@@ -163,6 +164,8 @@ public void testDesign() {
 
         when(nosd.areServicesSupportedByNetworkOffering(NETWORK_ID, 
Service.Connectivity)).thenReturn(true);
 
+        
when(netmodel.listNetworkOfferingServices(NETWORK_ID)).thenReturn(Arrays.asList(Service.Connectivity));
+
         final DeploymentPlan plan = mock(DeploymentPlan.class);
         final Network network = mock(Network.class);
         final Account account = mock(Account.class);
diff --git 
a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java
 
b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java
index f1737c1bf08..3d52f8415f8 100644
--- 
a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java
+++ 
b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/guru/NiciraNvpGuestNetworkGuruTest.java
@@ -94,7 +94,7 @@ public void setUp() {
         guru.niciraNvpDao = nvpdao;
         guru._dcDao = dcdao;
         guru.ntwkOfferingSrvcDao = nosd;
-        guru.networkModel = netmodel;
+        ((GuestNetworkGuru)guru)._networkModel = netmodel;
         guru.hostDao = hostdao;
         guru.agentMgr = agentmgr;
         guru.networkDao = netdao;
@@ -162,6 +162,8 @@ public void testDesign() {
 
         when(nosd.areServicesSupportedByNetworkOffering(NETWORK_ID, 
Service.Connectivity)).thenReturn(true);
 
+        
when(netmodel.listNetworkOfferingServices(NETWORK_ID)).thenReturn(Arrays.asList(Service.Connectivity));
+
         final DeploymentPlan plan = mock(DeploymentPlan.class);
         final Network network = mock(Network.class);
         final Account account = mock(Account.class);
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java 
b/server/src/com/cloud/api/ApiResponseHelper.java
index 3325be1069c..e755679a355 100644
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -2005,7 +2005,9 @@ public NetworkResponse createNetworkResponse(ResponseView 
view, Network network)
 
         // FIXME - either set netmask or cidr
         response.setCidr(network.getCidr());
-        response.setNetworkCidr((network.getNetworkCidr()));
+        if (network.getNetworkCidr() != null) {
+            response.setNetworkCidr((network.getNetworkCidr()));
+        }
         // If network has reservation its entire network cidr is defined by
         // getNetworkCidr()
         // if no reservation is present then getCidr() will define the entire
diff --git a/server/src/com/cloud/network/IpAddressManagerImpl.java 
b/server/src/com/cloud/network/IpAddressManagerImpl.java
index e34f90861c3..f0b5ee5cfe1 100644
--- a/server/src/com/cloud/network/IpAddressManagerImpl.java
+++ b/server/src/com/cloud/network/IpAddressManagerImpl.java
@@ -797,7 +797,6 @@ public IPAddressVO doInTransaction(TransactionStatus 
status) throws Insufficient
                         throw new AccountLimitException("Maximum number of 
public IP addresses for account: " + owner.getAccountName() + " has been 
exceeded.");
                     }
                 }
-
                 IPAddressVO addr = addrs.get(0);
                 addr.setSourceNat(sourceNat);
                 addr.setAllocatedTime(new Date());
@@ -1314,12 +1313,20 @@ public IPAddressVO associateIPToGuestNetwork(long ipId, 
long networkId, boolean
         if (zone.getNetworkType() == NetworkType.Advanced) {
             // In Advance zone allow to do IP assoc only for Isolated networks 
with source nat service enabled
             if (network.getGuestType() == GuestType.Isolated && 
!(_networkModel.areServicesSupportedInNetwork(network.getId(), 
Service.SourceNat))) {
+                if (releaseOnFailure && ipToAssoc != null) {
+                    s_logger.warn("Failed to associate ip address, so 
unassigning ip from the database " + ipToAssoc);
+                    _ipAddressDao.unassignIpAddress(ipToAssoc.getId());
+                }
                 throw new InvalidParameterValueException("In zone of type " + 
NetworkType.Advanced + " ip address can be associated only to the network of 
guest type "
                         + GuestType.Isolated + " with the " + 
Service.SourceNat.getName() + " enabled");
             }
 
             // In Advance zone allow to do IP assoc only for shared networks 
with source nat/static nat/lb/pf services enabled
             if (network.getGuestType() == GuestType.Shared && 
!isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) {
+                if (releaseOnFailure && ipToAssoc != null) {
+                    s_logger.warn("Failed to associate ip address, so 
unassigning ip from the database " + ipToAssoc);
+                    _ipAddressDao.unassignIpAddress(ipToAssoc.getId());
+                }
                 throw new InvalidParameterValueException("In zone of type " + 
NetworkType.Advanced + " ip address can be associated with network of guest 
type " + GuestType.Shared
                         + "only if at " + "least one of the services " + 
Service.SourceNat.getName() + "/" + Service.StaticNat.getName() + "/" + 
Service.Lb.getName() + "/"
                         + Service.PortForwarding.getName() + " is enabled");
@@ -1763,6 +1770,10 @@ public String acquireGuestIpAddress(Network network, 
String requestedIp) {
             return null;
         }
 
+        if 
(_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()
 && network.getCidr() == null) {
+            return null;
+        }
+
         Set<Long> availableIps = _networkModel.getAvailableIps(network, 
requestedIp);
 
         if (availableIps == null || availableIps.isEmpty()) {
diff --git a/server/src/com/cloud/network/NetworkModelImpl.java 
b/server/src/com/cloud/network/NetworkModelImpl.java
index 2efec9a0999..9330da175b3 100644
--- a/server/src/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/com/cloud/network/NetworkModelImpl.java
@@ -29,6 +29,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.Collections;
 
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
@@ -583,6 +584,9 @@ public boolean canUseForDeploy(Network network) {
         if (network.getTrafficType() != TrafficType.Guest) {
             return false;
         }
+        if 
(listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) {
+            return true; // do not check free IPs if there is no service in 
the network
+        }
         boolean hasFreeIps = true;
         if (network.getGuestType() == GuestType.Shared) {
             if (network.getGateway() != null) {
@@ -1823,6 +1827,9 @@ public boolean isNetworkAvailableInDomain(long networkId, 
long domainId) {
 
     @Override
     public Set<Long> getAvailableIps(Network network, String requestedIp) {
+        if (network.getCidr() == null) {
+            return Collections.emptySet();
+        }
         String[] cidr = network.getCidr().split("/");
         List<String> ips = getUsedIpsInNetwork(network);
         Set<Long> usedIps = new TreeSet<Long>();
diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java 
b/server/src/com/cloud/network/NetworkServiceImpl.java
index 966c0e4475b..7669fd340b5 100644
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -1124,7 +1124,7 @@ public Network createGuestNetwork(CreateNetworkCmd cmd) 
throws InsufficientCapac
                 }
             }
         } else {
-            if (ntwkOff.getGuestType() == GuestType.Isolated) {
+            if (ntwkOff.getGuestType() == GuestType.Isolated || 
ntwkOff.getGuestType() == GuestType.L2) {
                 aclType = ACLType.Account;
             } else if (ntwkOff.getGuestType() == GuestType.Shared) {
                 aclType = ACLType.Domain;
@@ -1861,9 +1861,9 @@ public boolean deleteNetwork(long networkId, boolean 
forced) {
 
         Account owner = _accountMgr.getAccount(network.getAccountId());
 
-        // Only Admin can delete Shared networks
-        if (network.getGuestType() == GuestType.Shared && 
!_accountMgr.isAdmin(caller.getId())) {
-            throw new InvalidParameterValueException("Only Admins can delete 
network with guest type " + GuestType.Shared);
+        // Only Admin can delete Shared and L2 networks
+        if ((network.getGuestType() == GuestType.Shared || 
network.getGuestType() == GuestType.L2) && 
!_accountMgr.isAdmin(caller.getId())) {
+            throw new InvalidParameterValueException("Only Admins can delete 
network with guest type " + network.getGuestType());
         }
 
         // Perform permission check
diff --git a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java 
b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java
index a6bc4f0d97e..6908a105fe7 100644
--- a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java
+++ b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java
@@ -91,8 +91,9 @@ public ExternalGuestNetworkGuru() {
     protected boolean canHandle(NetworkOffering offering, final NetworkType 
networkType, final PhysicalNetwork physicalNetwork) {
         // This guru handles only Guest Isolated network that supports Source
         // nat service
-        if (networkType == NetworkType.Advanced && 
isMyTrafficType(offering.getTrafficType()) && offering.getGuestType() == 
Network.GuestType.Isolated &&
-            isMyIsolationMethod(physicalNetwork) && !offering.isSystemOnly()) {
+        if (networkType == NetworkType.Advanced && 
isMyTrafficType(offering.getTrafficType())
+                && (offering.getGuestType() == Network.GuestType.Isolated || 
offering.getGuestType() == GuestType.L2)
+                && isMyIsolationMethod(physicalNetwork) && 
!offering.isSystemOnly()) {
             return true;
         } else {
             s_logger.trace("We only take care of Guest networks of type   " + 
GuestType.Isolated + " in zone of type " + NetworkType.Advanced);
@@ -295,12 +296,14 @@ public void reserve(NicProfile nic, Network config, 
VirtualMachineProfile vm, De
             nic.setIPv4Gateway(config.getGateway());
 
             if (nic.getIPv4Address() == null) {
-                String guestIp = _ipAddrMgr.acquireGuestIpAddress(config, 
null);
-                if (guestIp == null) {
-                    throw new 
InsufficientVirtualNetworkCapacityException("Unable to acquire guest IP address 
for network " + config, DataCenter.class, dc.getId());
-                }
+                if 
(!_networkModel.listNetworkOfferingServices(config.getNetworkOfferingId()).isEmpty())
 {
+                    String guestIp = _ipAddrMgr.acquireGuestIpAddress(config, 
null);
+                    if (guestIp == null) {
+                        throw new 
InsufficientVirtualNetworkCapacityException("Unable to acquire guest IP address 
for network " + config, DataCenter.class, dc.getId());
+                    }
 
-                nic.setIPv4Address(guestIp);
+                    nic.setIPv4Address(guestIp);
+                }
             } else {
                 long ipMask = NetUtils.ip2Long(nic.getIPv4Address()) & 
~(0xffffffffffffffffl << (32 - cidrSize));
                 nic.setIPv4Address(NetUtils.long2Ip(cidrAddress | ipMask));
diff --git a/server/src/com/cloud/network/guru/GuestNetworkGuru.java 
b/server/src/com/cloud/network/guru/GuestNetworkGuru.java
index 74d774065c1..c7e6aca22b8 100644
--- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java
+++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java
@@ -22,6 +22,7 @@
 
 import javax.inject.Inject;
 
+import com.cloud.network.Network.GuestType;
 import org.apache.cloudstack.context.CallContext;
 import 
org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.apache.cloudstack.framework.config.ConfigKey;
@@ -199,7 +200,7 @@ public Network design(final NetworkOffering offering, final 
DeploymentPlan plan,
             if (userSpecified.getCidr() != null) {
                 network.setCidr(userSpecified.getCidr());
                 network.setGateway(userSpecified.getGateway());
-            } else {
+            } else if (offering.getGuestType() == GuestType.Shared || 
!_networkModel.listNetworkOfferingServices(offering.getId()).isEmpty()) {
                 final String guestNetworkCidr = dc.getGuestNetworkCidr();
                 if (guestNetworkCidr != null) {
                     final String[] cidrTuple = guestNetworkCidr.split("\\/");
@@ -369,14 +370,16 @@ public NicProfile allocate(final Network network, 
NicProfile nic, final VirtualM
                     guestIp = network.getGateway();
                 } else {
                     guestIp = _ipAddrMgr.acquireGuestIpAddress(network, 
nic.getRequestedIPv4());
-                    if (guestIp == null) {
+                    if (guestIp == null && 
!_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty())
 {
                         throw new 
InsufficientVirtualNetworkCapacityException("Unable to acquire Guest IP" + " 
address for network " + network, DataCenter.class,
                                 dc.getId());
                     }
                 }
 
                 nic.setIPv4Address(guestIp);
-                
nic.setIPv4Netmask(NetUtils.cidr2Netmask(_networkModel.getValidNetworkCidr(network)));
+                if (network.getCidr() != null) {
+                    
nic.setIPv4Netmask(NetUtils.cidr2Netmask(_networkModel.getValidNetworkCidr(network)));
+                }
 
                 nic.setIPv4Dns1(dc.getDns1());
                 nic.setIPv4Dns2(dc.getDns2());
diff --git a/test/integration/smoke/test_network.py 
b/test/integration/smoke/test_network.py
index bb1e14b5d14..db939cf0d15 100644
--- a/test/integration/smoke/test_network.py
+++ b/test/integration/smoke/test_network.py
@@ -1271,3 +1271,225 @@ def test_network_rules_acquired_public_ip(self, value):
                 delay=0
             )
         return
+
+class TestL2Networks(cloudstackTestCase):
+
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+        self.services["network"]["networkoffering"] = self.network_offering.id
+
+        self.l2_network = Network.create(
+            self.apiclient,
+            self.services["l2-network"],
+            zoneid=self.zone.id,
+            networkofferingid=self.network_offering.id
+        )
+        self.cleanup = [
+            self.l2_network]
+
+    def tearDown(self):
+        cleanup_resources(self.apiclient, self.cleanup)
+        return
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestL2Networks, cls).getClsTestClient()
+        cls.apiclient = testClient.getApiClient()
+        cls.services = testClient.getParsedTestDataConfig()
+
+        # Get Zone, Domain and templates
+        cls.domain = get_domain(cls.apiclient)
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        # Create Accounts & networks
+        cls.account = Account.create(
+            cls.apiclient,
+            cls.services["account"],
+            admin=True,
+            domainid=cls.domain.id
+        )
+        cls.template = get_template(
+            cls.apiclient,
+            cls.zone.id,
+            cls.services["ostype"]
+        )
+        cls.service_offering = ServiceOffering.create(
+            cls.apiclient,
+            cls.services["service_offerings"]["tiny"]
+        )
+        cls.services["network"]["zoneid"] = cls.zone.id
+
+        cls.network_offering = NetworkOffering.create(
+            cls.apiclient,
+            cls.services["l2-network_offering"],
+        )
+        # Enable Network offering
+        cls.network_offering.update(cls.apiclient, state='Enabled')
+
+        cls._cleanup = [
+            cls.account,
+            cls.network_offering,
+            cls.service_offering
+        ]
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            # Cleanup resources used
+            cleanup_resources(cls.apiclient, cls._cleanup)
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
+    def test_deploy_vm_l2network(self):
+        """Creates an l2 network and verifies user is able to deploy a VM in 
it"""
+
+        # Validate the following:
+        # 1. Deploys a VM
+        # 2. There are no network services available since this is L2 Network
+
+        self.virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            serviceofferingid=self.service_offering.id,
+            networkids=self.l2_network.id,
+            zoneid=self.zone.id
+        )
+
+        self.cleanup.insert(0, self.virtual_machine)
+
+        list_vm = list_virtual_machines(
+            self.apiclient,
+            id = self.virtual_machine.id
+        )
+        self.assertEqual(
+            isinstance(list_vm, list),
+            True,
+            "Check if virtual machine is present"
+        )
+
+        self.assertEqual(
+            list_vm[0].nic[0].type,
+            'L2',
+            "Check Correct Network type is available"
+        )
+
+        self.assertFalse(
+            'gateway' in str(list_vm[0].nic[0])
+        )
+
+        self.assertFalse(
+            'ipaddress' in str(list_vm[0].nic[0])
+        )
+
+        return
+
+    @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
+    def test_delete_network_while_vm_on_it(self):
+        """It verifies the user is not able to delete network which has 
running vms"""
+
+        # Validate the following:
+        # 1. Deploys a VM
+        # 2. Tries to delete network and expects exception to appear
+
+        self.virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            serviceofferingid=self.service_offering.id,
+            networkids=self.l2_network.id,
+            zoneid=self.zone.id
+        )
+
+        self.cleanup.insert(0, self.virtual_machine)
+
+        list_vm = list_virtual_machines(
+            self.apiclient,
+            id = self.virtual_machine.id
+        )
+        self.assertEqual(
+            isinstance(list_vm, list),
+            True,
+            "Check if virtual machine is present"
+        )
+
+        try:
+            self.l2_network.delete(self.apiclient)
+        except Exception:
+            pass
+        else:
+            self.fail("Expected an exception to be thrown, failing")
+
+        return
+
+    @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
+    def test_l2network_restart(self):
+        """This test covers a few scenarios around restarting a network"""
+
+        # Validate the following:
+        # 1. Creates a l2 network
+        # 2. Tries to restart a network with no VMs, which trows error 'not in 
the right state'
+        # 3. Deploys a VM
+        # 4. Restarts the network without cleanup
+        # 5. Restarts the network with cleanup
+
+        try:
+            self.l2_network.restart(self.apiclient, cleanup=True)
+        except Exception:
+            pass
+        else:
+            self.fail("Expected an exception to be thrown, failing")
+
+        li_net = self.l2_network.list(self.apiclient)[0]
+
+        self.assertTrue(
+            li_net.state,
+            'Allocated'
+            "Not the correct state"
+        )
+
+        self.virtual_machine = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine"],
+            templateid=self.template.id,
+            serviceofferingid=self.service_offering.id,
+            networkids=self.l2_network.id,
+            zoneid=self.zone.id
+        )
+
+        self.cleanup.insert(0, self.virtual_machine)
+
+        list_vm = list_virtual_machines(
+            self.apiclient,
+            id = self.virtual_machine.id
+        )
+        self.assertEqual(
+            isinstance(list_vm, list),
+            True,
+            "Check if virtual machine is present"
+        )
+
+        self.l2_network.restart(self.apiclient, cleanup=False)
+
+        li_net = self.l2_network.list(self.apiclient)[0]
+
+        self.assertTrue(
+            li_net.state,
+            'Implemented'
+            "Not the correct state"
+        )
+
+        self.l2_network.restart(self.apiclient, cleanup=True)
+
+        li_net = self.l2_network.list(self.apiclient)[0]
+
+        self.assertTrue(
+            li_net.state,
+            'Implemented'
+            "Not the correct state"
+        )
+
+        return
diff --git a/tools/marvin/marvin/config/test_data.py 
b/tools/marvin/marvin/config/test_data.py
index da74cb52daa..ece3e327771 100644
--- a/tools/marvin/marvin/config/test_data.py
+++ b/tools/marvin/marvin/config/test_data.py
@@ -190,6 +190,10 @@
         "displaytext": "Test Network",
         "acltype": "Account",
     },
+    "l2-network": {
+        "name": "Test L2 Network",
+        "displaytext": "Test L2 Network"
+    },
     "network2": {
         "name": "Test Network Shared",
         "displaytext": "Test Network Shared",
@@ -200,6 +204,14 @@
         "endip": "172.16.15.41",
         "acltype": "Account",
     },
+    "l2-network_offering": {
+        "name": 'Test L2 - Network offering',
+        "displaytext": 'Test L2 - Network offering',
+        "guestiptype": 'L2',
+        "supportedservices": '',
+        "traffictype": 'GUEST',
+        "availability": 'Optional'
+    },
     "network_offering": {
         "name": 'Test Network offering',
         "displaytext": 'Test Network offering',
diff --git a/ui/l10n/ar.js b/ui/l10n/ar.js
index afb4269ec68..727660eab2e 100644
--- a/ui/l10n/ar.js
+++ b/ui/l10n/ar.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Add Isolated Guest Network",
     "label.add.isolated.guest.network.with.sourcenat": "Add Isolated Guest 
Network with SourceNat",
     "label.add.isolated.network": "Add Isolated Network",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Add LDAP account",
     "label.add.list.name": "ACL List Name",
     "label.add.load.balancer": "Add Load Balancer",
diff --git a/ui/l10n/ca.js b/ui/l10n/ca.js
index 3b1f04caa0f..771743f3aff 100644
--- a/ui/l10n/ca.js
+++ b/ui/l10n/ca.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Add Isolated Guest Network",
     "label.add.isolated.guest.network.with.sourcenat": "Add Isolated Guest 
Network with SourceNat",
     "label.add.isolated.network": "Add Isolated Network",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Add LDAP account",
     "label.add.list.name": "ACL List Name",
     "label.add.load.balancer": "Add Load Balancer",
diff --git a/ui/l10n/de_DE.js b/ui/l10n/de_DE.js
index c0f2e0ae012..727dc2afead 100644
--- a/ui/l10n/de_DE.js
+++ b/ui/l10n/de_DE.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Isoliertes Gastnetzwerk hinzufügen",
     "label.add.isolated.guest.network.with.sourcenat": "Isoliertes 
Gastnetzwerk mit Source-NAT hinzufügen",
     "label.add.isolated.network": "Isoliertes Netzwerk hinzufügen",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "LDAP-Konto hinzufügen",
     "label.add.list.name": "ACL-Listename",
     "label.add.load.balancer": "Lastverteiler hinzufügen",
diff --git a/ui/l10n/en.js b/ui/l10n/en.js
index 3d0c42147c7..26a7a038d4e 100644
--- a/ui/l10n/en.js
+++ b/ui/l10n/en.js
@@ -340,6 +340,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
 "label.add.isolated.guest.network":"Add Isolated Guest Network",
 "label.add.isolated.guest.network.with.sourcenat":"Add Isolated Guest Network 
with SourceNat",
 "label.add.isolated.network":"Add Isolated Network",
+"label.add.l2.guest.network":"Add L2 Guest Network",
 "label.add.ldap.account":"Add LDAP account",
 "label.add.list.name":"ACL List Name",
 "label.add.load.balancer":"Add Load Balancer",
diff --git a/ui/l10n/es.js b/ui/l10n/es.js
index 6abfd8eaaf0..0d53b0e6aa6 100644
--- a/ui/l10n/es.js
+++ b/ui/l10n/es.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Añadir Red Invitado Aislada",
     "label.add.isolated.guest.network.with.sourcenat": "Agregar Red de 
Invitado Aislada con NatOrigen",
     "label.add.isolated.network": "Agregar Red Aislada",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Agregar cuenta LDAP",
     "label.add.list.name": "Nombre de la Lista ACL",
     "label.add.load.balancer": "Añadir balanceador de carga",
diff --git a/ui/l10n/fr_FR.js b/ui/l10n/fr_FR.js
index dd5e85a3555..ac6f17323f6 100644
--- a/ui/l10n/fr_FR.js
+++ b/ui/l10n/fr_FR.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Ajouter un réseau d'invité isolé",
     "label.add.isolated.guest.network.with.sourcenat": "Ajouter un réseau 
d'invité isolé avec SourceNat",
     "label.add.isolated.network": "Ajouter un réseau isolé",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Ajouter un compte LDAP",
     "label.add.list.name": "Nom Liste ACL",
     "label.add.load.balancer": "Ajouter un répartiteur de charge",
diff --git a/ui/l10n/hu.js b/ui/l10n/hu.js
index 23519b951e1..db4f2188a21 100644
--- a/ui/l10n/hu.js
+++ b/ui/l10n/hu.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Izolált vendég hálózat felvétele",
     "label.add.isolated.guest.network.with.sourcenat": "Add Isolated Guest 
Network with SourceNat",
     "label.add.isolated.network": "Izolált hálózat felvétele",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "LDAP hozzáférés felvétele",
     "label.add.list.name": "ACL lista név",
     "label.add.load.balancer": "Terheléselosztó felvétele",
diff --git a/ui/l10n/it_IT.js b/ui/l10n/it_IT.js
index c4501e63b38..7a8caa545de 100644
--- a/ui/l10n/it_IT.js
+++ b/ui/l10n/it_IT.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Add Isolated Guest Network",
     "label.add.isolated.guest.network.with.sourcenat": "Add Isolated Guest 
Network with SourceNat",
     "label.add.isolated.network": "Add Isolated Network",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Aggiungi un account LDAP",
     "label.add.list.name": "ACL List Name",
     "label.add.load.balancer": "Aggiungere un Load Balancer",
diff --git a/ui/l10n/ja_JP.js b/ui/l10n/ja_JP.js
index a2f42f9e34b..7498c8f3e03 100644
--- a/ui/l10n/ja_JP.js
+++ b/ui/l10n/ja_JP.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "分離ゲストネットワークの追加",
     "label.add.isolated.guest.network.with.sourcenat": 
"分離ゲストネットワーク(送信元NAT)の追加",
     "label.add.isolated.network": "分離されたネットワークの追加",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "LDAP アカウントの追加",
     "label.add.list.name": "ACL 一覧名",
     "label.add.load.balancer": "ロード バランサーの追加",
diff --git a/ui/l10n/ko_KR.js b/ui/l10n/ko_KR.js
index 9655052fbc7..372a728f7c4 100644
--- a/ui/l10n/ko_KR.js
+++ b/ui/l10n/ko_KR.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Add Isolated Guest Network",
     "label.add.isolated.guest.network.with.sourcenat": "Add Isolated Guest 
Network with SourceNat",
     "label.add.isolated.network": "Add Isolated Network",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Add LDAP account",
     "label.add.list.name": "ACL List Name",
     "label.add.load.balancer": "네트워크 로드 공유 장치 추가",
diff --git a/ui/l10n/nb_NO.js b/ui/l10n/nb_NO.js
index c9836eada37..d0d1d3fbf6f 100644
--- a/ui/l10n/nb_NO.js
+++ b/ui/l10n/nb_NO.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Legg til Isolert gjestenettverk",
     "label.add.isolated.guest.network.with.sourcenat": "Legg til isolert 
gjestenettverk med kilde-NAT",
     "label.add.isolated.network": "Legg Til Isolert Nettverk",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Legg til LDAP-konto",
     "label.add.list.name": "ACL listenavn",
     "label.add.load.balancer": "Legg til lastbalanserer",
diff --git a/ui/l10n/nl_NL.js b/ui/l10n/nl_NL.js
index 5e438899ee5..62313e996ad 100644
--- a/ui/l10n/nl_NL.js
+++ b/ui/l10n/nl_NL.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Voeg een geïsoleerd netwerk toe",
     "label.add.isolated.guest.network.with.sourcenat": "voeg en geïsoleerd 
gast netwerk met bron-NAT toe",
     "label.add.isolated.network": "Geisoleerd Netwerk Toevoegen",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Voeg LDAP account toe",
     "label.add.list.name": "ACL lijst naam",
     "label.add.load.balancer": "Voeg Load Balancer toe",
diff --git a/ui/l10n/pl.js b/ui/l10n/pl.js
index 8b1cb420559..75c3af1f1e8 100644
--- a/ui/l10n/pl.js
+++ b/ui/l10n/pl.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Add Isolated Guest Network",
     "label.add.isolated.guest.network.with.sourcenat": "Add Isolated Guest 
Network with SourceNat",
     "label.add.isolated.network": "Add Isolated Network",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Add LDAP account",
     "label.add.list.name": "ACL List Name",
     "label.add.load.balancer": "Add Load Balancer",
diff --git a/ui/l10n/pt_BR.js b/ui/l10n/pt_BR.js
index fbaafcb8913..1b0be1897f4 100644
--- a/ui/l10n/pt_BR.js
+++ b/ui/l10n/pt_BR.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Adiciona Rede Guest Isolada",
     "label.add.isolated.guest.network.with.sourcenat": "Adicionar rede Guest 
isolada com SourceNat",
     "label.add.isolated.network": "Adiciona Rede Isolada",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Adicionar Conta LDAP",
     "label.add.list.name": "Nome de Lista ACL",
     "label.add.load.balancer": "Adicionar Load Balance",
diff --git a/ui/l10n/ru_RU.js b/ui/l10n/ru_RU.js
index 649e5fe170d..62c2602f6d6 100644
--- a/ui/l10n/ru_RU.js
+++ b/ui/l10n/ru_RU.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "Добавить изолированную гостевую сеть",
     "label.add.isolated.guest.network.with.sourcenat": "Add Isolated Guest 
Network with SourceNat",
     "label.add.isolated.network": "Добавить изолированную сеть",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "Добавить LDAP аккаунт",
     "label.add.list.name": "ACL List Name",
     "label.add.load.balancer": "Добавить балансировщик нагрузки",
diff --git a/ui/l10n/zh_CN.js b/ui/l10n/zh_CN.js
index c4a663c4a8c..78729d9a500 100644
--- a/ui/l10n/zh_CN.js
+++ b/ui/l10n/zh_CN.js
@@ -338,6 +338,7 @@ var dictionary = {
     "label.add.isolated.guest.network": "添加隔离的来宾网络",
     "label.add.isolated.guest.network.with.sourcenat": "添加隔离的来宾网络并启用 
SourceNat",
     "label.add.isolated.network": "添加隔离网络",
+    "label.add.l2.guest.network":"Add L2 Guest Network",
     "label.add.ldap.account": "添加 LDAP 账户",
     "label.add.list.name": "ACL 列表名称",
     "label.add.load.balancer": "添加负载平衡器",
diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js
index 00972b66050..cbe32813b04 100644
--- a/ui/scripts/configuration.js
+++ b/ui/scripts/configuration.js
@@ -2403,13 +2403,19 @@
                                         //*** VPC checkbox ***
                                         var $useVpc = 
args.$form.find('.form-item[rel=\"useVpc\"]');
                                         var $useVpcCb = 
$useVpc.find("input[type=checkbox]");
+                                        var $supportedServices = 
args.$form.find('.form-item[rel=\"supportedServices\"]');
                                         if ($guestTypeField.val() == 'Shared') 
{ //Shared network offering
                                             $useVpc.hide();
+                                            $supportedServices.css('display', 
'inline-block');
                                             if ($useVpcCb.is(':checked')) { 
//if useVpc is checked,
                                                 
$useVpcCb.removeAttr("checked"); //remove "checked" attribute in useVpc
                                             }
-                                        } else { //Isolated network offering
+                                        } else if ($guestTypeField.val() == 
'Isolated') { //Isolated network offering
                                             $useVpc.css('display', 
'inline-block');
+                                            $supportedServices.css('display', 
'inline-block');
+                                        } else if ($guestTypeField.val() == 
'L2') {
+                                            $useVpc.hide();
+                                            $supportedServices.hide();
                                         }
                                         var $providers = 
$useVpcCb.closest('form').find('.dynamic-input 
select[name!="service.Connectivity.provider"]');
                                         var $optionsOfProviders = 
$providers.find('option');
@@ -2754,6 +2760,9 @@
                                                 }, {
                                                     id: 'Shared',
                                                     description: 'Shared'
+                                                }, {
+                                                    id: 'L2',
+                                                    description: 'L2'
                                                 }]
                                             });
 
@@ -2766,10 +2775,9 @@
                                                     
$form.find('.form-item[rel=isPersistent]').find('input[type=checkbox]').attr("disabled",
 "disabled");
 
 
-                                                } else { //$(this).val() == 
"Isolated"
+                                                } else if ($(this).val() == 
"Isolated" || $(this).val() == "L2") {
                                                     
$form.find('.form-item[rel=specifyVlan]').find('input[type=checkbox]').removeAttr("disabled");
 //make it editable
                                                     
$form.find('.form-item[rel=isPersistent]').find('input[type=checkbox]').removeAttr("disabled");
-
                                                 }
                                             });
                                         }
@@ -3370,6 +3378,12 @@
                                     } else { //Isolated Network with 
Non-persistent network
                                         delete inputData.isPersistent; //if 
Persistent checkbox is unchecked, do not pass isPersistent parameter to API 
call since we need to keep API call's size as small as possible (p.s. 
isPersistent is defaulted as false at server-side)
                                     }
+                                } else if (inputData['guestIpType'] == "L2") {
+                                    if (inputData['specifyVlan'] == 'on') { 
//specifyVlan checkbox is checked
+                                        inputData['specifyVlan'] = true;
+                                    } else { //specifyVlan checkbox is 
unchecked
+                                        delete inputData.specifyVlan; //if 
specifyVlan checkbox is unchecked, do not pass specifyVlan parameter to API 
call since we need to keep API call's size as small as possible (p.s. 
specifyVlan is defaulted as false at server-side)
+                                    }
                                 }
 
                                 if (inputData['forvpc'] == 'on') {
diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js
index ca77c27e6b1..db7f5335148 100644
--- a/ui/scripts/instances.js
+++ b/ui/scripts/instances.js
@@ -431,6 +431,9 @@
                         var items = 
json.listvirtualmachinesresponse.virtualmachine;
                         if (items) {
                             $.each(items, function(idx, vm) {
+                                if (! vm.ipaddress) {
+                                    vm['ipaddress'] = "N/A";
+                                }
                                 if (vm.nic && vm.nic.length > 0 && 
vm.nic[0].ipaddress) {
                                     items[idx].ipaddress = vm.nic[0].ipaddress;
                                 }
diff --git a/ui/scripts/network.js b/ui/scripts/network.js
index 66ab75a42f0..9054a8537bb 100644
--- a/ui/scripts/network.js
+++ b/ui/scripts/network.js
@@ -800,6 +800,10 @@
 
                         rootAdminAddGuestNetwork: $.extend({}, 
addGuestNetworkDialog.def, {
                             isHeader: true
+                        }),
+
+                        rootAdminAddL2Network: $.extend({}, 
addL2GuestNetwork.def, {
+                            isHeader: true
                         })
 
                     },
@@ -954,7 +958,8 @@
                             path: 'network.ipAddresses',
                             label: 'label.menu.ipaddresses',
                             preFilter: function(args) {
-                                if (args.context.networks[0].state == 
'Destroyed')
+                                if (args.context.networks[0].state == 
'Destroyed' ||
+                                    args.context.networks[0].type == 'L2')
                                     return false;
 
                                 return true;
@@ -971,6 +976,11 @@
                                         return 'label.edit.network.details';
                                     }
                                 },
+                                preFilter: function(args) {
+                                    if (args.context.networks[0].state == 
'Destroyed')
+                                        return false;
+                                    return true;
+                                },
                                 action: function(args) {
                                     var data = {
                                         id: args.context.networks[0].id,
@@ -1051,8 +1061,13 @@
                                 }
                             },
 
-                            'restart': {
+                            restart: {
                                 label: 'label.restart.network',
+                                preFilter: function(args) {
+                                    if (args.context.networks[0].state == 
'Destroyed')
+                                        return false;
+                                    return true;
+                                },
                                 createForm: {
                                     title: 'label.restart.network',
                                     desc: 'message.restart.network',
@@ -1108,6 +1123,11 @@
 
                             remove: {
                                 label: 'label.action.delete.network',
+                                preFilter: function(args) {
+                                    if (args.context.networks[0].state == 
'Destroyed')
+                                        return false;
+                                    return true;
+                                },
                                 messages: {
                                     confirm: function(args) {
                                         return 'message.action.delete.network';
diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js
index 655aee9fb93..c58ce056c8e 100644
--- a/ui/scripts/sharedFunctions.js
+++ b/ui/scripts/sharedFunctions.js
@@ -818,6 +818,263 @@ var addGuestNetworkDialog = {
     }
 }
 
+var addL2GuestNetwork = {
+    zoneObjs: [],
+    physicalNetworkObjs: [],
+    networkOfferingObjs: [],
+    def: {
+        label: 'label.add.l2.guest.network',
+
+        messages: {
+            notification: function(args) {
+                return 'label.add.l2.guest.network';
+            }
+        },
+
+        preFilter: function(args) {
+            if (isAdmin())
+                return true;
+            else
+                return false;
+        },
+
+        createForm: {
+            title: 'label.add.l2.guest.network',
+            fields: {
+                name: {
+                    label: 'label.name',
+                    validation: {
+                        required: true
+                    },
+                    docID: 'helpGuestNetworkName'
+                },
+                displayText: {
+                    label: 'label.display.text',
+                    validation: {
+                        required: true
+                    },
+                    docID: 'helpGuestNetworkDisplayText'
+                },
+                zoneId: {
+                    label: 'label.zone',
+                    validation: {
+                        required: true
+                    },
+                    docID: 'helpGuestNetworkZone',
+
+                    select: function(args) {
+                        $.ajax({
+                            url: createURL('listZones'),
+                            success: function(json) {
+                                var zones = 
$.grep(json.listzonesresponse.zone, function(zone) {
+                                    return (zone.networktype == 'Advanced' && 
zone.securitygroupsenabled != true); //Isolated networks can only be created in 
Advanced SG-disabled zone (but not in Basic zone nor Advanced SG-enabled zone)
+                                });
+
+                                args.response.success({
+                                    data: $.map(zones, function(zone) {
+                                        return {
+                                            id: zone.id,
+                                            description: zone.name
+                                        };
+                                    })
+                                });
+                            }
+                        });
+                    }
+                },
+                networkOfferingId: {
+                    label: 'label.network.offering',
+                    validation: {
+                        required: true
+                    },
+                    dependsOn: 'zoneId',
+                    docID: 'helpGuestNetworkNetworkOffering',
+                    select: function(args) {
+                        var data = {
+                            zoneid: args.zoneId,
+                            guestiptype: 'L2',
+                            state: 'Enabled'
+                        };
+
+                        if ('vpc' in args.context) { //from VPC section
+                            $.extend(data, {
+                                forVpc: true
+                            });
+                        }
+                        else { //from guest network section
+                            var vpcs;
+                            $.ajax({
+                                url: createURL('listVPCs'),
+                                data: {
+                                    listAll: true
+                                },
+                                async: false,
+                                success: function(json) {
+                                    vpcs = json.listvpcsresponse.vpc;
+                                }
+                            });
+                            if (vpcs == null || vpcs.length == 0) { //if there 
is no VPC in the system
+                                $.extend(data, {
+                                    forVpc: false
+                                });
+                            }
+                        }
+
+                        if(!isAdmin()) { //normal user is not aware of the 
VLANs in the system, so normal user is not allowed to create network with 
network offerings whose specifyvlan = true
+                            $.extend(data, {
+                                specifyvlan: false
+                            });
+                        }
+
+                        $.ajax({
+                            url: createURL('listNetworkOfferings'),
+                            data: data,
+                            success: function(json) {
+                                networkOfferingObjs = 
json.listnetworkofferingsresponse.networkoffering;
+                                args.$select.change(function() {
+                                    var $vlan = 
args.$select.closest('form').find('[rel=vlan]');
+                                    var networkOffering = $.grep(
+                                        networkOfferingObjs, 
function(netoffer) {
+                                            return netoffer.id == 
args.$select.val();
+                                        }
+                                    )[0];
+
+                                    if (networkOffering.specifyvlan) {
+                                        $vlan.css('display', 'inline-block');
+                                    } else {
+                                        $vlan.hide();
+                                    }
+                                });
+
+                                args.response.success({
+                                    data: $.map(networkOfferingObjs, 
function(zone) {
+                                        return {
+                                            id: zone.id,
+                                            description: zone.name
+                                        };
+                                    })
+                                });
+                            }
+                        });
+                    }
+                },
+
+                vlan: {
+                    label: 'label.vlan',
+                    validation: {
+                        required: true
+                    },
+                    isHidden: true
+                },
+
+                domain: {
+                    label: 'label.domain',
+                    isHidden: function(args) {
+                        if (isAdmin() || isDomainAdmin())
+                            return false;
+                        else
+                            return true;
+                    },
+                    select: function(args) {
+                        if (isAdmin() || isDomainAdmin()) {
+                            $.ajax({
+                                url: createURL("listDomains&listAll=true"),
+                                success: function(json) {
+                                    var items = [];
+                                    items.push({
+                                        id: "",
+                                        description: ""
+                                    });
+                                    var domainObjs = 
json.listdomainsresponse.domain;
+                                    $(domainObjs).each(function() {
+                                        items.push({
+                                            id: this.id,
+                                            description: this.path
+                                        });
+                                    });
+                                    items.sort(function(a, b) {
+                                        return 
a.description.localeCompare(b.description);
+                                    });
+                                    args.response.success({
+                                        data: items
+                                    });
+                                }
+                            });
+                            args.$select.change(function() {
+                                var $form = $(this).closest('form');
+                                if ($(this).val() == "") {
+                                    
$form.find('.form-item[rel=account]').hide();
+                                } else {
+                                    
$form.find('.form-item[rel=account]').css('display', 'inline-block');
+                                }
+                            });
+                        } else {
+                            args.response.success({
+                                data: null
+                            });
+                        }
+                    }
+                },
+                account: {
+                    label: 'label.account',
+                    validation: {
+                        required: true
+                    },
+                    isHidden: function(args) {
+                        if (isAdmin() || isDomainAdmin())
+                            return false;
+                        else
+                            return true;
+                    }
+                }
+            }
+        },
+
+        action: function(args) {
+            var dataObj = {
+                zoneId: args.data.zoneId,
+                name: args.data.name,
+                displayText: args.data.displayText,
+                networkOfferingId: args.data.networkOfferingId
+            };
+
+            if (args.$form.find('.form-item[rel=vlan]').css('display') != 
'none') {
+                $.extend(dataObj, {
+                    vlan: args.data.vlan
+                });
+            }
+
+            if (args.data.domain != null && args.data.domain.length > 0) {
+                $.extend(dataObj, {
+                    domainid: args.data.domain
+                });
+                if (args.data.account != null && args.data.account.length > 0) 
{
+                    $.extend(dataObj, {
+                        account: args.data.account
+                    });
+                }
+            }
+
+            $.ajax({
+                url: createURL('createNetwork'),
+                data: dataObj,
+                success: function(json) {
+                    args.response.success({
+                        data: json.createnetworkresponse.network
+                    });
+                },
+                error: function(json) {
+                    args.response.error(parseXMLHttpResponse(json));
+                }
+            });
+        },
+        notification: {
+            poll: function(args) {
+                args.complete();
+            }
+        }
+    }
+}
 
     function isLdapEnabled() {
         var result;


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


> New Network Type (L2)
> ---------------------
>
>                 Key: CLOUDSTACK-10102
>                 URL: https://issues.apache.org/jira/browse/CLOUDSTACK-10102
>             Project: CloudStack
>          Issue Type: Improvement
>      Security Level: Public(Anyone can view this level - this is the 
> default.) 
>            Reporter: Nicolas Vazquez
>            Assignee: Nicolas Vazquez
>
> Feature Specification: 
> https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=74680920



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

Reply via email to