You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by GitBox <gi...@apache.org> on 2018/01/06 17:44:35 UTC

[GitHub] rhtyd closed pull request #2295: CLOUDSTACK-10109: Enable dedication of public IPs to SSVM and CPVM

rhtyd closed pull request #2295: CLOUDSTACK-10109: Enable dedication of public IPs to SSVM and CPVM
URL: https://github.com/apache/cloudstack/pull/2295
 
 
   

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/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java
index a2da7dbc8da..fa66fdde1a7 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java
@@ -112,6 +112,9 @@
     @Parameter(name = ApiConstants.IP6_CIDR, type = CommandType.STRING, description = "the CIDR of IPv6 network, must be at least /64")
     private String ip6Cidr;
 
+    @Parameter(name = ApiConstants.FOR_SYSTEM_VMS, type = CommandType.BOOLEAN, description = "true if IP range is set to system vms, false if not")
+    private Boolean forSystemVms;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -136,6 +139,10 @@ public String getGateway() {
         return gateway;
     }
 
+    public Boolean isForSystemVms() {
+        return forSystemVms == null ? Boolean.FALSE : forSystemVms;
+    }
+
     public String getNetmask() {
         return netmask;
     }
diff --git a/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java b/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java
index 59214847a92..5656a92955d 100644
--- a/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java
@@ -116,10 +116,22 @@
     @Param(description = "the cidr of IPv6 network")
     private String ip6Cidr;
 
+    @SerializedName(ApiConstants.FOR_SYSTEM_VMS)
+    @Param(description = "indicates whether VLAN IP range is dedicated to system vms or not")
+    private Boolean forSystemVms;
+
     public void setId(String id) {
         this.id = id;
     }
 
+    public Boolean getForSystemVms() {
+        return forSystemVms;
+    }
+
+    public void setForSystemVms(Boolean forSystemVms) {
+        this.forSystemVms = forSystemVms;
+    }
+
     public void setForVirtualNetwork(Boolean forVirtualNetwork) {
         this.forVirtualNetwork = forVirtualNetwork;
     }
diff --git a/engine/components-api/src/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/com/cloud/configuration/ConfigurationManager.java
index 0c7ed3a3dc1..235b241264c 100644
--- a/engine/components-api/src/com/cloud/configuration/ConfigurationManager.java
+++ b/engine/components-api/src/com/cloud/configuration/ConfigurationManager.java
@@ -213,7 +213,7 @@ NetworkOfferingVO createNetworkOffering(String name, String displayText, Traffic
             boolean conserveMode, Map<Service, Map<Capability, String>> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent,
             Map<NetworkOffering.Detail, String> details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc);
 
-    Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP,
+    Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP,
         String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr)
         throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException;
 
diff --git a/engine/components-api/src/com/cloud/network/IpAddressManager.java b/engine/components-api/src/com/cloud/network/IpAddressManager.java
index d469cbac62b..256f0266635 100644
--- a/engine/components-api/src/com/cloud/network/IpAddressManager.java
+++ b/engine/components-api/src/com/cloud/network/IpAddressManager.java
@@ -61,7 +61,7 @@
      * @return
      * @throws InsufficientAddressCapacityException
      */
-    PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem)
+    PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem, boolean forSystemVms)
             throws InsufficientAddressCapacityException;
 
     /**
diff --git a/engine/schema/resources/META-INF/db/schema-41000to41100.sql b/engine/schema/resources/META-INF/db/schema-41000to41100.sql
index 283844e96d6..6c6655c8e46 100644
--- a/engine/schema/resources/META-INF/db/schema-41000to41100.sql
+++ b/engine/schema/resources/META-INF/db/schema-41000to41100.sql
@@ -524,6 +524,10 @@ ADD COLUMN `forsystemvms` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'Indicates if
 ALTER TABLE `cloud`.`op_dc_ip_address_alloc`
 ADD COLUMN `vlan` INT(10) UNSIGNED NULL COMMENT 'Vlan the management network range is on';
 
+-- CLOUDSTACK-10109: Enable dedication of public IPs to SSVM and CPVM
+ALTER TABLE `cloud`.`user_ip_address`
+ADD COLUMN `forsystemvms` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'true if IP is set to system vms, false if not';
+
 -- ldap binding on domain level
 CREATE TABLE IF NOT EXISTS `cloud`.`domain_details` (
     `id` bigint unsigned NOT NULL auto_increment,
@@ -539,4 +543,3 @@ ALTER TABLE cloud.ldap_trust_map ADD COLUMN account_id BIGINT(20) DEFAULT 0;
 ALTER TABLE cloud.ldap_trust_map DROP FOREIGN KEY fk_ldap_trust_map__domain_id;
 DROP INDEX uk_ldap_trust_map__domain_id ON cloud.ldap_trust_map;
 CREATE UNIQUE INDEX uk_ldap_trust_map__bind_location ON ldap_trust_map (domain_id, account_id);
-
diff --git a/engine/schema/src/com/cloud/network/dao/IPAddressVO.java b/engine/schema/src/com/cloud/network/dao/IPAddressVO.java
index 95834a0ca67..0b880116159 100644
--- a/engine/schema/src/com/cloud/network/dao/IPAddressVO.java
+++ b/engine/schema/src/com/cloud/network/dao/IPAddressVO.java
@@ -122,6 +122,9 @@
     @Column(name = "rule_state")
     State ruleState;
 
+    @Column(name = "forsystemvms")
+    private boolean forSystemVms = false;
+
     @Column(name= GenericDao.REMOVED_COLUMN)
     private Date removed;
 
@@ -382,4 +385,8 @@ public State getRuleState() {
     public void setRuleState(State ruleState) {
         this.ruleState = ruleState;
     }
+
+    public boolean isForSystemVms() {
+        return forSystemVms;
+    }
 }
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java
index e1477926091..68acee88abe 100644
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java
@@ -154,7 +154,7 @@ private void getBaremetalIp(NicProfile nic, Pod pod, VirtualMachineProfile vm, N
         DataCenter dc = _dcDao.findById(pod.getDataCenterId());
         if (nic.getIPv4Address() == null) {
             s_logger.debug(String.format("Requiring ip address: %s", nic.getIPv4Address()));
-            PublicIp ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), requiredIp, false);
+            PublicIp ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), requiredIp, false, false);
             nic.setIPv4Address(ip.getAddress().toString());
             nic.setFormat(AddressFormat.Ip4);
             nic.setIPv4Gateway(ip.getGateway());
diff --git a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/LoadBalanceRuleHandler.java b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/LoadBalanceRuleHandler.java
index f5046b6a7b4..dc5f0ab6cee 100644
--- a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/LoadBalanceRuleHandler.java
+++ b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/LoadBalanceRuleHandler.java
@@ -446,7 +446,7 @@ private PublicIp allocDirectIp(final Account account, final long guestNetworkId)
             public PublicIp doInTransaction(final TransactionStatus status) throws InsufficientAddressCapacityException {
                 final Network frontEndNetwork = _networkModel.getNetwork(guestNetworkId);
 
-                final PublicIp ip = _ipAddrMgr.assignPublicIpAddress(frontEndNetwork.getDataCenterId(), null, account, VlanType.DirectAttached, frontEndNetwork.getId(), null, true);
+                final PublicIp ip = _ipAddrMgr.assignPublicIpAddress(frontEndNetwork.getDataCenterId(), null, account, VlanType.DirectAttached, frontEndNetwork.getId(), null, true, false);
                 final IPAddressVO ipvo = _ipAddressDao.findById(ip.getId());
                 ipvo.setAssociatedWithNetworkId(frontEndNetwork.getId());
                 _ipAddressDao.update(ipvo.getId(), ipvo);
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index 49b8c150ecc..5b1ec2e68b6 100644
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -98,6 +98,7 @@
 import com.cloud.network.as.Condition;
 import com.cloud.network.as.ConditionVO;
 import com.cloud.network.as.Counter;
+import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.LoadBalancerVO;
 import com.cloud.network.dao.NetworkVO;
@@ -163,6 +164,8 @@
 import com.cloud.utils.StringUtils;
 import com.cloud.utils.db.EntityManager;
 import com.cloud.utils.net.Dhcp;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.Ip;
 import com.cloud.utils.net.NetUtils;
@@ -356,6 +359,8 @@
     private ResourceTagDao _resourceTagDao;
     @Inject
     private NicExtraDhcpOptionDao _nicExtraDhcpOptionDao;
+    @Inject
+    private IPAddressDao userIpAddressDao;
 
     @Override
     public UserResponse createUserResponse(User user) {
@@ -745,6 +750,7 @@ public VlanIpRangeResponse createVlanIpRangeResponse(Class<? extends VlanIpRange
                     vlanResponse.setPhysicalNetworkId(pnw.getUuid());
                 }
             }
+            vlanResponse.setForSystemVms(isForSystemVms(vlan.getId()));
             vlanResponse.setObjectName("vlan");
             return vlanResponse;
         } catch (InstantiationException | IllegalAccessException e) {
@@ -752,6 +758,20 @@ public VlanIpRangeResponse createVlanIpRangeResponse(Class<? extends VlanIpRange
         }
     }
 
+    /**
+     * Return true if vlan IP range is dedicated for system vms (SSVM and CPVM), false if not
+     * @param vlanId vlan id
+     * @return true if VLAN IP range is dedicated to system vms
+     */
+    private boolean isForSystemVms(long vlanId){
+        SearchBuilder<IPAddressVO> sb = userIpAddressDao.createSearchBuilder();
+        sb.and("vlanId", sb.entity().getVlanId(), SearchCriteria.Op.EQ);
+        SearchCriteria<IPAddressVO> sc = sb.create();
+        sc.setParameters("vlanId", vlanId);
+        IPAddressVO userIpAddresVO = userIpAddressDao.findOneBy(sc);
+        return userIpAddresVO.isForSystemVms();
+    }
+
     @Override
     public IPAddressResponse createIPAddressResponse(ResponseView view, IpAddress ipAddr) {
         VlanVO vlan = ApiDBUtils.findVlanById(ipAddr.getVlanId());
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index 9d9ac52fae5..412ca5bead7 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -2908,9 +2908,14 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In
         String endIPv6 = cmd.getEndIpv6();
         final String ip6Gateway = cmd.getIp6Gateway();
         final String ip6Cidr = cmd.getIp6Cidr();
+        final Boolean forSystemVms = cmd.isForSystemVms();
 
         Account vlanOwner = null;
 
+        if (forSystemVms && accountName != null) {
+            throw new InvalidParameterValueException("Account name should not be provided when ForSystemVMs is enabled");
+        }
+
         final boolean ipv4 = startIP != null;
         final boolean ipv6 = startIPv6 != null;
 
@@ -3118,12 +3123,12 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In
             checkOverlapPrivateIpRange(zoneId, startIP, endIP);
         }
 
-        return commitVlan(zoneId, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, forVirtualNetwork, networkId, physicalNetworkId, startIPv6, endIPv6, ip6Gateway,
+        return commitVlan(zoneId, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, forVirtualNetwork, forSystemVms, networkId, physicalNetworkId, startIPv6, endIPv6, ip6Gateway,
                 ip6Cidr, domain, vlanOwner, network, sameSubnet);
     }
 
     private Vlan commitVlan(final Long zoneId, final Long podId, final String startIP, final String endIP, final String newVlanGatewayFinal, final String newVlanNetmaskFinal,
-            final String vlanId, final Boolean forVirtualNetwork, final Long networkId, final Long physicalNetworkId, final String startIPv6, final String endIPv6,
+            final String vlanId, final Boolean forVirtualNetwork, final Boolean forSystemVms, final Long networkId, final Long physicalNetworkId, final String startIPv6, final String endIPv6,
             final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair<Boolean, Pair<String, String>> sameSubnet) {
         final GlobalLock commitVlanLock = GlobalLock.getInternLock("CommitVlan");
         commitVlanLock.lock(5);
@@ -3151,7 +3156,7 @@ public Vlan doInTransaction(final TransactionStatus status) {
                         newVlanGateway = sameSubnet.second().first();
                         newVlanNetmask = sameSubnet.second().second();
                     }
-                    final Vlan vlan = createVlanAndPublicIpRange(zoneId, networkId, physicalNetworkId, forVirtualNetwork, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId,
+                    final Vlan vlan = createVlanAndPublicIpRange(zoneId, networkId, physicalNetworkId, forVirtualNetwork, forSystemVms, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId,
                             false, domain, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr);
                     // create an entry in the nic_secondary table. This will be the new
                     // gateway that will be configured on the corresponding routervm.
@@ -3271,7 +3276,7 @@ public boolean hasSameSubnet(boolean ipv4, String vlanGateway, String vlanNetmas
 
     @Override
     @DB
-    public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final boolean forVirtualNetwork, final Long podId, final String startIP, final String endIP,
+    public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final boolean forVirtualNetwork, final boolean forSystemVms, final Long podId, final String startIP, final String endIP,
             final String vlanGateway, final String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, final Account vlanOwner, final String startIPv6, final String endIPv6, final String vlanIp6Gateway, final String vlanIp6Cidr) {
         final Network network = _networkModel.getNetwork(networkId);
 
@@ -3521,14 +3526,14 @@ public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId,
 
         // Everything was fine, so persist the VLAN
         final VlanVO vlan = commitVlanAndIpRange(zoneId, networkId, physicalNetworkId, podId, startIP, endIP, vlanGateway, vlanNetmask, vlanId, domain, vlanOwner, vlanIp6Gateway, vlanIp6Cidr,
-                ipv4, zone, vlanType, ipv6Range, ipRange);
+                ipv4, zone, vlanType, ipv6Range, ipRange, forSystemVms);
 
         return vlan;
     }
 
     private VlanVO commitVlanAndIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final Long podId, final String startIP, final String endIP,
             final String vlanGateway, final String vlanNetmask, final String vlanId, final Domain domain, final Account vlanOwner, final String vlanIp6Gateway, final String vlanIp6Cidr,
-            final boolean ipv4, final DataCenterVO zone, final VlanType vlanType, final String ipv6Range, final String ipRange) {
+            final boolean ipv4, final DataCenterVO zone, final VlanType vlanType, final String ipv6Range, final String ipRange, final boolean forSystemVms) {
         return Transaction.execute(new TransactionCallback<VlanVO>() {
             @Override
             public VlanVO doInTransaction(final TransactionStatus status) {
@@ -3539,7 +3544,7 @@ public VlanVO doInTransaction(final TransactionStatus status) {
                 // IPv6 use a used ip map, is different from ipv4, no need to save
                 // public ip range
                 if (ipv4) {
-                    if (!savePublicIPRange(startIP, endIP, zoneId, vlan.getId(), networkId, physicalNetworkId)) {
+                    if (!savePublicIPRange(startIP, endIP, zoneId, vlan.getId(), networkId, physicalNetworkId, forSystemVms)) {
                         throw new CloudRuntimeException("Failed to save IPv4 range. Please contact Cloud Support.");
                     }
                 }
@@ -3561,8 +3566,8 @@ public VlanVO doInTransaction(final TransactionStatus status) {
                     _resourceLimitMgr.incrementResourceCount(vlanOwner.getId(), ResourceType.public_ip, new Long(ips.size()));
                 } else if (domain != null) {
                     // This VLAN is domain-wide, so create a DomainVlanMapVO entry
-                    final DomainVlanMapVO domainVlanMapVO = new DomainVlanMapVO(domain.getId(), vlan.getId());
-                    _domainVlanMapDao.persist(domainVlanMapVO);
+                    //final DomainVlanMapVO domainVlanMapVO = new DomainVlanMapVO(domain.getId(), vlan.getId());
+                    //_domainVlanMapDao.persist(domainVlanMapVO);
                 } else if (podId != null) {
                     // This VLAN is pod-wide, so create a PodVlanMapVO entry
                     final PodVlanMapVO podVlanMapVO = new PodVlanMapVO(podId, vlan.getId());
@@ -3873,7 +3878,7 @@ public boolean releasePublicIpRange(final long vlanDbId, final long userId, fina
     }
 
     @DB
-    protected boolean savePublicIPRange(final String startIP, final String endIP, final long zoneId, final long vlanDbId, final long sourceNetworkid, final long physicalNetworkId) {
+    protected boolean savePublicIPRange(final String startIP, final String endIP, final long zoneId, final long vlanDbId, final long sourceNetworkid, final long physicalNetworkId, final boolean forSystemVms) {
         final long startIPLong = NetUtils.ip2Long(startIP);
         final long endIPLong = NetUtils.ip2Long(endIP);
 
@@ -3881,7 +3886,7 @@ protected boolean savePublicIPRange(final String startIP, final String endIP, fi
             @Override
             public List<String> doInTransaction(final TransactionStatus status) {
                 final IPRangeConfig config = new IPRangeConfig();
-                return config.savePublicIPRange(TransactionLegacy.currentTxn(), startIPLong, endIPLong, zoneId, vlanDbId, sourceNetworkid, physicalNetworkId);
+                return config.savePublicIPRange(TransactionLegacy.currentTxn(), startIPLong, endIPLong, zoneId, vlanDbId, sourceNetworkid, physicalNetworkId, forSystemVms);
             }
         });
 
diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java
index 1e6271de6a2..166fab734d4 100644
--- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java
+++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java
@@ -538,7 +538,7 @@ public ExternalLoadBalancerDeviceVO doInTransaction(TransactionStatus status) th
                             // acquire a public IP to associate with lb appliance (used as subnet IP to make the appliance part of private network)
                             PublicIp publicIp =
                                 _ipAddrMgr.assignPublicIpAddress(guestConfig.getDataCenterId(), null, _accountMgr.getSystemAccount(), VlanType.VirtualNetwork, null,
-                                    null, false);
+                                    null, false, false);
                             String publicIPNetmask = publicIp.getVlanNetmask();
                             String publicIPgateway = publicIp.getVlanGateway();
                             String publicIP = publicIp.getAddress().toString();
@@ -813,7 +813,7 @@ private MappingNic getLoadBalancingIpNic(DataCenterVO zone, Network network, lon
                         try {
                             PublicIp directIp =
                                 _ipAddrMgr.assignPublicIpAddress(network.getDataCenterId(), null, _accountDao.findById(network.getAccountId()), VlanType.DirectAttached,
-                                    network.getId(), null, true);
+                                    network.getId(), null, true, false);
                             loadBalancingIpAddress = directIp.getAddress().addr();
                         } catch (InsufficientCapacityException capException) {
                             String msg = "Ran out of guest IP addresses from the shared network.";
diff --git a/server/src/com/cloud/network/IpAddressManagerImpl.java b/server/src/com/cloud/network/IpAddressManagerImpl.java
index dca994d6a5a..891dddf66f8 100644
--- a/server/src/com/cloud/network/IpAddressManagerImpl.java
+++ b/server/src/com/cloud/network/IpAddressManagerImpl.java
@@ -295,6 +295,10 @@
 
     static Boolean rulesContinueOnErrFlag = true;
 
+    private static final ConfigKey<Boolean> SystemVmPublicIpReservationModeStrictness = new ConfigKey<Boolean>("Advanced",
+            Boolean.class, "system.vm.public.ip.reservation.mode.strictness", "false",
+            "If enabled, the use of System VMs public IP reservation is strict, preferred if not.", false, ConfigKey.Scope.Global);
+
     @Override
     public boolean configure(String name, Map<String, Object> params) {
         // populate providers
@@ -395,6 +399,9 @@ public boolean configure(String name, Map<String, Object> params) {
         AssignIpAddressSearch.and("dc", AssignIpAddressSearch.entity().getDataCenterId(), Op.EQ);
         AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL);
         AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN);
+        if (SystemVmPublicIpReservationModeStrictness.value()) {
+            AssignIpAddressSearch.and("forSystemVms", AssignIpAddressSearch.entity().isForSystemVms(), Op.EQ);
+        }
         SearchBuilder<VlanVO> vlanSearch = _vlanDao.createSearchBuilder();
         vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ);
         vlanSearch.and("networkId", vlanSearch.entity().getNetworkId(), Op.EQ);
@@ -675,20 +682,20 @@ public Boolean doInTransaction(TransactionStatus status) {
     }
 
     @Override
-    public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem)
+    public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem, boolean forSystemVms)
             throws InsufficientAddressCapacityException {
-        return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp, isSystem, null, null);
+        return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp, isSystem, null, null, forSystemVms);
     }
 
     @Override
     public PublicIp assignPublicIpAddressFromVlans(long dcId, Long podId, Account owner, VlanType type, List<Long> vlanDbIds, Long networkId, String requestedIp, boolean isSystem)
             throws InsufficientAddressCapacityException {
-        return fetchNewPublicIp(dcId, podId, vlanDbIds, owner, type, networkId, false, true, requestedIp, isSystem, null, null);
+        return fetchNewPublicIp(dcId, podId, vlanDbIds, owner, type, networkId, false, true, requestedIp, isSystem, null, null, false);
     }
 
     @DB
     public PublicIp fetchNewPublicIp(final long dcId, final Long podId, final List<Long> vlanDbIds, final Account owner, final VlanType vlanUse, final Long guestNetworkId,
-            final boolean sourceNat, final boolean assign, final String requestedIp, final boolean isSystem, final Long vpcId, final Boolean displayIp)
+            final boolean sourceNat, final boolean assign, final String requestedIp, final boolean isSystem, final Long vpcId, final Boolean displayIp, final boolean forSystemVms)
                     throws InsufficientAddressCapacityException {
         IPAddressVO addr = Transaction.execute(new TransactionCallbackWithException<IPAddressVO, InsufficientAddressCapacityException>() {
             @Override
@@ -758,7 +765,13 @@ public IPAddressVO doInTransaction(TransactionStatus status) throws Insufficient
                     errorMessage.append(": requested ip " + requestedIp + " is not available");
                 }
 
-                Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l);
+                boolean ascOrder = ! forSystemVms;
+                Filter filter = new Filter(IPAddressVO.class, "forSystemVms", ascOrder, 0l, 1l);
+                if (SystemVmPublicIpReservationModeStrictness.value()) {
+                    sc.setParameters("forSystemVms", forSystemVms);
+                }
+
+                filter.addOrderBy(IPAddressVO.class,"vlanId", true);
 
                 List<IPAddressVO> addrs = _ipAddressDao.search(sc, filter, false);
 
@@ -951,7 +964,13 @@ public PublicIp doInTransaction(TransactionStatus status) throws InsufficientAdd
                         VpcVO vpc = _vpcDao.findById(vpcId);
                         displayIp = vpc.isDisplay();
                     }
-                    return fetchNewPublicIp(dcId, null, null, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, true, null, false, vpcId, displayIp);
+                    PublicIp ip = fetchNewPublicIp(dcId, null, null, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, false, null, false, vpcId, displayIp, false);
+                    IPAddressVO publicIp = ip.ip();
+
+                    markPublicIpAsAllocated(publicIp);
+                    _ipAddressDao.update(publicIp.getId(), publicIp);
+
+                    return ip;
                 }
             });
             if (ip.getState() != State.Allocated) {
@@ -1147,7 +1166,7 @@ public IpAddress allocateIp(final Account ipOwner, final boolean isSystem, Accou
             ip = Transaction.execute(new TransactionCallbackWithException<PublicIp, InsufficientAddressCapacityException>() {
                 @Override
                 public PublicIp doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException {
-                    PublicIp ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, false, assign, null, isSystem, null, displayIp);
+                    PublicIp ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, false, assign, null, isSystem, null, displayIp, false);
 
                     if (ip == null) {
                         InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zone
@@ -2009,7 +2028,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Insuff
                         }
 
                         if (ip == null) {
-                            ip = assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIpv4, false);
+                            ip = assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIpv4, false, false);
                         }
 
                         nic.setIPv4Address(ip.getAddress().toString());
@@ -2142,7 +2161,7 @@ public int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, Firew
 
     @Override
     public String allocatePublicIpForGuestNic(Network network, Long podId, Account owner, String requestedIp) throws InsufficientAddressCapacityException {
-        PublicIp ip = assignPublicIpAddress(network.getDataCenterId(), podId, owner, VlanType.DirectAttached, network.getId(), requestedIp, false);
+        PublicIp ip = assignPublicIpAddress(network.getDataCenterId(), podId, owner, VlanType.DirectAttached, network.getId(), requestedIp, false, false);
         if (ip == null) {
             s_logger.debug("There is no free public ip address");
             return null;
@@ -2163,6 +2182,6 @@ public String getConfigComponentName() {
 
     @Override
     public ConfigKey<?>[] getConfigKeys() {
-        return new ConfigKey<?>[] {UseSystemPublicIps, RulesContinueOnError};
+        return new ConfigKey<?>[] {UseSystemPublicIps, RulesContinueOnError, SystemVmPublicIpReservationModeStrictness};
     }
 }
diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java
index 6b431f43a7e..707055fc593 100644
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -1386,7 +1386,7 @@ public Network doInTransaction(TransactionStatus status) throws InsufficientCapa
 
                     if (_accountMgr.isRootAdmin(caller.getId()) && createVlan && network != null) {
                         // Create vlan ip range
-                        _configMgr.createVlanAndPublicIpRange(pNtwk.getDataCenterId(), network.getId(), physicalNetworkId, false, null, startIP, endIP, gateway, netmask, vlanId,
+                        _configMgr.createVlanAndPublicIpRange(pNtwk.getDataCenterId(), network.getId(), physicalNetworkId, false, false, null, startIP, endIP, gateway, netmask, vlanId,
                                 bypassVlanOverlapCheck, null, null, startIPv6, endIPv6, ip6Gateway, ip6Cidr);
                     }
                     return network;
diff --git a/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java b/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
index f9657be4775..a797b24471a 100644
--- a/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
+++ b/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
@@ -194,7 +194,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Insuff
                         }
 
                         if (ip == null) {
-                            ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), null, false);
+                            ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), null, false, false);
                         }
 
                         nic.setIPv4Address(ip.getAddress().toString());
diff --git a/server/src/com/cloud/network/guru/PublicNetworkGuru.java b/server/src/com/cloud/network/guru/PublicNetworkGuru.java
index c27543dbbdb..96146f0b065 100644
--- a/server/src/com/cloud/network/guru/PublicNetworkGuru.java
+++ b/server/src/com/cloud/network/guru/PublicNetworkGuru.java
@@ -115,7 +115,11 @@ protected PublicNetworkGuru() {
     protected void getIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network) throws InsufficientVirtualNetworkCapacityException,
         InsufficientAddressCapacityException, ConcurrentOperationException {
         if (nic.getIPv4Address() == null) {
-            PublicIp ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.VirtualNetwork, null, null, false);
+            boolean forSystemVms = false;
+            if (vm.getType().equals(VirtualMachine.Type.ConsoleProxy) || vm.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) {
+                forSystemVms = true;
+            }
+            PublicIp ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.VirtualNetwork, null, null, false, forSystemVms);
             nic.setIPv4Address(ip.getAddress().toString());
             nic.setIPv4Gateway(ip.getGateway());
             nic.setIPv4Netmask(ip.getNetmask());
diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java
index 854ec136b49..e348051cb0d 100644
--- a/server/src/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/com/cloud/server/ConfigurationServerImpl.java
@@ -290,7 +290,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
                             long startIPLong = NetUtils.ip2Long(startIp);
                             long endIPLong = NetUtils.ip2Long(endIp);
                             config.savePublicIPRange(TransactionLegacy.currentTxn(), startIPLong, endIPLong, vlan.getDataCenterId(), vlan.getId(), vlan.getNetworkId(),
-                                    vlan.getPhysicalNetworkId());
+                                    vlan.getPhysicalNetworkId(), false);
                         }
                     });
 
diff --git a/server/src/com/cloud/test/IPRangeConfig.java b/server/src/com/cloud/test/IPRangeConfig.java
index 29feba6119e..020c828a828 100644
--- a/server/src/com/cloud/test/IPRangeConfig.java
+++ b/server/src/com/cloud/test/IPRangeConfig.java
@@ -431,7 +431,7 @@ private boolean isPrivateIPAllocated(String ip, long podId, long zoneId, Prepare
         List<String> problemIPs = null;
 
         if (type.equals("public")) {
-            problemIPs = savePublicIPRange(txn, startIPLong, endIPLong, zoneId, vlanDbId, sourceNetworkId, physicalNetworkId);
+            problemIPs = savePublicIPRange(txn, startIPLong, endIPLong, zoneId, vlanDbId, sourceNetworkId, physicalNetworkId, false);
         } else if (type.equals("private")) {
             problemIPs = savePrivateIPRange(txn, startIPLong, endIPLong, podId, zoneId);
         }
@@ -445,9 +445,9 @@ private boolean isPrivateIPAllocated(String ip, long podId, long zoneId, Prepare
         return problemIPs;
     }
 
-    public Vector<String> savePublicIPRange(TransactionLegacy txn, long startIP, long endIP, long zoneId, long vlanDbId, Long sourceNetworkId, long physicalNetworkId) {
+    public Vector<String> savePublicIPRange(TransactionLegacy txn, long startIP, long endIP, long zoneId, long vlanDbId, Long sourceNetworkId, long physicalNetworkId, boolean forSystemVms) {
         String insertSql =
-            "INSERT INTO `cloud`.`user_ip_address` (public_ip_address, data_center_id, vlan_db_id, mac_address, source_network_id, physical_network_id, uuid) VALUES (?, ?, ?, (select mac_address from `cloud`.`data_center` where id=?), ?, ?, ?)";
+            "INSERT INTO `cloud`.`user_ip_address` (public_ip_address, data_center_id, vlan_db_id, mac_address, source_network_id, physical_network_id, uuid, forsystemvms) VALUES (?, ?, ?, (select mac_address from `cloud`.`data_center` where id=?), ?, ?, ?, ?)";
         String updateSql = "UPDATE `cloud`.`data_center` set mac_address = mac_address+1 where id=?";
         Vector<String> problemIPs = new Vector<String>();
 
@@ -468,6 +468,7 @@ private boolean isPrivateIPAllocated(String ip, long podId, long zoneId, Prepare
                 insert_stmt.setLong(5, sourceNetworkId);
                 insert_stmt.setLong(6, physicalNetworkId);
                 insert_stmt.setString(7, UUID.randomUUID().toString());
+                insert_stmt.setBoolean(8, forSystemVms);
                 insert_stmt.executeUpdate();
                 update_stmt.setLong(1, zoneId);
                 update_stmt.executeUpdate();
diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
index a624986c446..9057241cc78 100644
--- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
@@ -459,7 +459,7 @@ public NetworkOfferingVO createNetworkOffering(String name, String displayText,
      * @see com.cloud.configuration.ConfigurationManager#createVlanAndPublicIpRange(long, long, long, boolean, java.lang.Long, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.cloud.user.Account)
      */
     @Override
-    public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP,
+    public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP,
         String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6)
         throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException {
         // TODO Auto-generated method stub
diff --git a/test/integration/smoke/test_public_ip_range.py b/test/integration/smoke/test_public_ip_range.py
index e09f7b43b5d..624a407dc4a 100644
--- a/test/integration/smoke/test_public_ip_range.py
+++ b/test/integration/smoke/test_public_ip_range.py
@@ -25,6 +25,8 @@
 from marvin.lib.base import *
 from marvin.lib.common import *
 import datetime
+from socket import inet_aton
+from struct import unpack
 
 class TestDedicatePublicIPRange(cloudstackTestCase):
 
@@ -147,3 +149,241 @@ def test_dedicatePublicIpRange(self):
 
         return
 
+    @attr(tags = ["advanced", "publiciprange", "dedicate", "release"], required_hardware="false")
+    def test_dedicate_public_ip_range_for_system_vms(self):
+        """Test public IP range dedication for SSVM and CPVM
+        """
+
+        # Validate the following:
+        # 1. Create a Public IP range for system vms
+        # 2. Created IP range should be present and marked as forsystemvms=true, verify with listVlanIpRanges
+        # 7. Delete the Public IP range
+        
+        services = {
+            "gateway":"192.168.99.1",
+            "netmask":"255.255.255.0",
+            "startip":"192.168.99.2",
+            "endip":"192.168.99.200",
+            "forvirtualnetwork":self.services["forvirtualnetwork"],
+            "zoneid":self.services["zoneid"],
+            "vlan":self.services["vlan"]
+        }
+        public_ip_range = PublicIpRange.create(
+            self.apiclient,
+            services,
+            forsystemvms = True
+        )
+        created_ip_range_response = PublicIpRange.list(
+            self.apiclient,
+            id = public_ip_range.vlan.id
+        )
+        self.assertEqual(
+            len(created_ip_range_response),
+            1,
+            "Check listVlanIpRanges response"
+        )
+        self.assertTrue(
+            created_ip_range_response[0].forsystemvms,
+            "Check forsystemvms parameter in created vlan ip range"
+        )
+        
+        # Delete range
+        public_ip_range.delete(self.apiclient)
+        
+    def get_ip_as_number(self, ip_string):
+        """ Return numeric value for ip (passed as a string)
+        """
+        packed_ip = inet_aton(ip_string)
+        return unpack(">L", packed_ip)[0]
+    
+    def is_ip_in_range(self, start_ip, end_ip, ip_to_test):
+        """ Check whether ip_to_test belongs to IP range between start_ip and end_ip
+        """
+        start = self.get_ip_as_number(start_ip)
+        end = self.get_ip_as_number(end_ip)
+        ip = self.get_ip_as_number(ip_to_test)
+        return start <= ip and ip <= end
+    
+    def wait_for_system_vm_start(self, domain_id, srv_timeout, srv_sleep, systemvmtype):
+        """ Wait until system vm is Running
+        """
+        timeout = srv_timeout
+        while True:
+            list_systemvm_response = list_ssvms(
+                self.apiclient,
+                systemvmtype=systemvmtype,
+                domainid=domain_id
+            )
+            if isinstance(list_systemvm_response, list):
+                if list_systemvm_response[0].state == 'Running':
+                    return list_systemvm_response[0].id
+            if timeout == 0:
+                raise Exception("List System VM call failed!")
+
+            time.sleep(srv_sleep)
+            timeout = timeout - 1
+        return None
+
+    def base_system_vm(self, services, systemvmtype):
+        """
+        Base for CPVM or SSVM depending on systemvmtype parameter
+        """
+
+        # Create range for system vms
+        self.debug("Creating Public IP range for system vms")
+        public_ip_range = PublicIpRange.create(
+            self.apiclient,
+            services,
+            forsystemvms = True
+        )
+
+        # List Running System VM
+        list_systemvm_response = list_ssvms(
+            self.apiclient,
+            systemvmtype=systemvmtype,
+            state='Running',
+            domainid=public_ip_range.vlan.domainid
+        )
+        self.assertTrue(
+            isinstance(list_systemvm_response, list),
+            "Check list response returns a valid list"
+        )
+        self.assertEqual(
+            len(list_systemvm_response),
+            1,
+            "Check list response size"
+        )
+
+        # Delete System VM
+        systemvm = list_systemvm_response[0]
+        self.debug("Destroying System VM: %s" % systemvm.id)
+        cmd = destroySystemVm.destroySystemVmCmd()
+        cmd.id = systemvm.id
+        self.apiclient.destroySystemVm(cmd)
+
+        # Wait for CPVM to start
+        systemvm_id = self.wait_for_system_vm_start(
+            public_ip_range.vlan.domainid,
+            self.services["timeout"],
+            self.services["sleep"],
+            systemvmtype
+        )
+        self.assertNotEqual(
+            systemvm_id,
+            None,
+            "Check CPVM id is not none"
+        )
+        list_systemvm_response = list_ssvms(
+            self.apiclient,
+            id=systemvm_id
+        )
+        self.assertEqual(
+            isinstance(list_systemvm_response, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        systemvm_response = list_systemvm_response[0]
+        self.debug("System VM state after debug: %s" % systemvm_response.state)
+        self.assertEqual(
+            systemvm_response.state,
+            'Running',
+            "Check whether System VM is running or not"
+        )
+
+        # Verify System VM got IP in the created range
+        startip = services["startip"]
+        endip = services["endip"]
+        cpvm_ip = systemvm_response.publicip
+
+        self.assertTrue(
+            self.is_ip_in_range(startip, endip, cpvm_ip),
+            "Check whether System VM Public IP is in range dedicated to system vms"
+        )
+
+        # Delete System VM and IP range, so System VM can get IP from original ranges
+        self.debug("Destroying System VM: %s" % systemvm_id)
+        cmd = destroySystemVm.destroySystemVmCmd()
+        cmd.id = systemvm_id
+        self.apiclient.destroySystemVm(cmd)
+
+        domain_id = public_ip_range.vlan.domainid
+        public_ip_range.delete(self.apiclient)
+
+        # Wait for System VM to start and check System VM public IP
+        systemvm_id = self.wait_for_system_vm_start(
+            domain_id,
+            self.services["timeout"],
+            self.services["sleep"],
+            systemvmtype
+        )
+        list_systemvm_response = list_ssvms(
+            self.apiclient,
+            id=systemvm_id
+        )
+        self.assertFalse(
+            self.is_ip_in_range(startip, endip, list_systemvm_response[0].publicip),
+            "Check System VM Public IP is not in range dedicated to system vms"
+        )
+
+        return True
+
+    def exists_public_ip_range_for_system_vms(self, zoneid):
+        """
+        Return True if there exists a public IP range dedicated for system vms in zoneid
+        """
+        existing_ip_ranges_response = PublicIpRange.list(
+            self.apiclient,
+            zoneid=zoneid
+        )
+        for r in existing_ip_ranges_response:
+            if r.forsystemvms:
+                return True
+        return False
+
+    @attr(tags = ["advanced", "publiciprange", "dedicate", "release"], required_hardware="false")
+    def test_dedicate_public_ip_range_for_system_vms_cpvm(self):
+        """Test CPVM Public IP
+        """
+        self.debug("Precondition: No public IP range dedicated for system vms in the environment")
+        if self.exists_public_ip_range_for_system_vms(self.services["zoneid"]):
+            self.skipTest("An existing IP range defined for system vms, aborting test")
+        
+        services = {
+            "gateway":"192.168.100.1",
+            "netmask":"255.255.255.0",
+            "startip":"192.168.100.2",
+            "endip":"192.168.100.200",
+            "forvirtualnetwork":self.services["forvirtualnetwork"],
+            "zoneid":self.services["zoneid"],
+            "vlan":self.services["vlan"]
+        }
+
+        self.base_system_vm(
+            services,
+            'consoleproxy'
+        )
+        return
+
+    @attr(tags = ["advanced", "publiciprange", "dedicate", "release"], required_hardware="false")
+    def test_dedicate_public_ip_range_for_system_vms_ssvm(self):
+        """Test SSVM Public IP
+        """
+        self.debug("Precondition: No public IP range dedicated for system vms in the environment")
+        if self.exists_public_ip_range_for_system_vms(self.services["zoneid"]):
+            self.skipTest("An existing IP range defined for system vms, aborting test")
+
+        services = {
+            "gateway":"192.168.200.1",
+            "netmask":"255.255.255.0",
+            "startip":"192.168.200.2",
+            "endip":"192.168.200.200",
+            "forvirtualnetwork":self.services["forvirtualnetwork"],
+            "zoneid":self.services["zoneid"],
+            "vlan":self.services["vlan"]
+        }
+
+        self.base_system_vm(
+            services,
+            'secondarystoragevm'
+        )
+        return
\ No newline at end of file
diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py
index 2c5f5345f07..a3f1043e654 100755
--- a/tools/marvin/marvin/lib/base.py
+++ b/tools/marvin/marvin/lib/base.py
@@ -3383,7 +3383,7 @@ def __init__(self, items):
         self.__dict__.update(items)
 
     @classmethod
-    def create(cls, apiclient, services, account=None, domainid=None):
+    def create(cls, apiclient, services, account=None, domainid=None, forsystemvms=None):
         """Create VlanIpRange"""
 
         cmd = createVlanIpRange.createVlanIpRangeCmd()
@@ -3401,6 +3401,8 @@ def create(cls, apiclient, services, account=None, domainid=None):
             cmd.account = account
         if domainid:
             cmd.domainid = domainid
+        if forsystemvms:
+            cmd.forsystemvms = forsystemvms
 
         return PublicIpRange(apiclient.createVlanIpRange(cmd).__dict__)
 
diff --git a/ui/l10n/ar.js b/ui/l10n/ar.js
index 727660eab2e..ef30387221d 100644
--- a/ui/l10n/ar.js
+++ b/ui/l10n/ar.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Services",
     "label.session.expired": "Session Expired",
     "label.set.default.NIC": "Set default NIC",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Set up zone type",
     "label.settings": "Settings",
     "label.setup": "???????",
diff --git a/ui/l10n/ca.js b/ui/l10n/ca.js
index 771743f3aff..7bd14365185 100644
--- a/ui/l10n/ca.js
+++ b/ui/l10n/ca.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Services",
     "label.session.expired": "Session Expired",
     "label.set.default.NIC": "Set default NIC",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Set up zone type",
     "label.settings": "Settings",
     "label.setup": "Configuraci?",
diff --git a/ui/l10n/de_DE.js b/ui/l10n/de_DE.js
index 727dc2afead..5bf300cffbe 100644
--- a/ui/l10n/de_DE.js
+++ b/ui/l10n/de_DE.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Dienste",
     "label.session.expired": "Sitzung abgelaufen",
     "label.set.default.NIC": "Standard-NIC festlegen",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Zonentyp einrichten",
     "label.settings": "Einstellungen",
     "label.setup": "Konfiguration",
diff --git a/ui/l10n/en.js b/ui/l10n/en.js
index 1f31dce7e73..9e2e4ae9cc9 100644
--- a/ui/l10n/en.js
+++ b/ui/l10n/en.js
@@ -1528,6 +1528,8 @@ var dictionary = {"ICMP.code":"ICMP Code",
 "label.services":"Services",
 "label.session.expired":"Session Expired",
 "label.set.default.NIC":"Set default NIC",
+"label.set.reservation": "Set reservation",
+"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
 "label.set.up.zone.type":"Set up zone type",
 "label.settings":"Settings",
 "label.setup":"Setup",
diff --git a/ui/l10n/es.js b/ui/l10n/es.js
index 0d53b0e6aa6..599f9cb0420 100644
--- a/ui/l10n/es.js
+++ b/ui/l10n/es.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Servicios",
     "label.session.expired": "Session Caducada",
     "label.set.default.NIC": "Definir NIC por defecto",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Definir tipo de zona",
     "label.settings": "Configuraci?n",
     "label.setup": "Configuraci?n",
diff --git a/ui/l10n/fr_FR.js b/ui/l10n/fr_FR.js
index ac6f17323f6..8f22fb73197 100644
--- a/ui/l10n/fr_FR.js
+++ b/ui/l10n/fr_FR.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Services",
     "label.session.expired": "Session expir?e",
     "label.set.default.NIC": "D?finir NIC par d?faut",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Configurer le type de zone",
     "label.settings": "Param?tres",
     "label.setup": "Configuration",
diff --git a/ui/l10n/hu.js b/ui/l10n/hu.js
index db4f2188a21..b1f83243f07 100644
--- a/ui/l10n/hu.js
+++ b/ui/l10n/hu.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Szolg?ltat?sok",
     "label.session.expired": "A munkamenet lej?rt",
     "label.set.default.NIC": "Alap?rtelmezett NIC be?ll?t?sa",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Z?na-t?pus be?ll?t?sa",
     "label.settings": "Be?ll?t?sok",
     "label.setup": "Be?ll?t?sok",
diff --git a/ui/l10n/it_IT.js b/ui/l10n/it_IT.js
index 7a8caa545de..02b7e50a81f 100644
--- a/ui/l10n/it_IT.js
+++ b/ui/l10n/it_IT.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Services",
     "label.session.expired": "Session Expired",
     "label.set.default.NIC": "Set default NIC",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Configurazione del tipo di Zona",
     "label.settings": "Settings",
     "label.setup": "Installazione",
diff --git a/ui/l10n/ja_JP.js b/ui/l10n/ja_JP.js
index 7498c8f3e03..da27a9f1d43 100644
--- a/ui/l10n/ja_JP.js
+++ b/ui/l10n/ja_JP.js
@@ -1489,6 +1489,8 @@ var dictionary = {
     "label.services": "????",
     "label.session.expired": "????????????????",
     "label.set.default.NIC": "????? NIC ???",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "?????????????",
     "label.settings": "??",
     "label.setup": "??????",
diff --git a/ui/l10n/ko_KR.js b/ui/l10n/ko_KR.js
index 372a728f7c4..caa38bbeca2 100644
--- a/ui/l10n/ko_KR.js
+++ b/ui/l10n/ko_KR.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Services",
     "label.session.expired": "?? ????? ???",
     "label.set.default.NIC": "Set default NIC",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Zone ?? ??",
     "label.settings": "Settings",
     "label.setup": "??",
diff --git a/ui/l10n/nb_NO.js b/ui/l10n/nb_NO.js
index d0d1d3fbf6f..49a8b8530cf 100644
--- a/ui/l10n/nb_NO.js
+++ b/ui/l10n/nb_NO.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Tjenester",
     "label.session.expired": "Sesjon utl?pt",
     "label.set.default.NIC": "Sett som standard NIC",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Oppsett av sonetype",
     "label.settings": "Innstillinger",
     "label.setup": "Oppsett",
diff --git a/ui/l10n/nl_NL.js b/ui/l10n/nl_NL.js
index 62313e996ad..3d20ff394c4 100644
--- a/ui/l10n/nl_NL.js
+++ b/ui/l10n/nl_NL.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Diensten",
     "label.session.expired": "Sessie Verlopen",
     "label.set.default.NIC": "Stel standaard NIC in",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Stel zone type in",
     "label.settings": "Instellingen",
     "label.setup": "Instellen",
diff --git a/ui/l10n/pl.js b/ui/l10n/pl.js
index 75c3af1f1e8..7faa8c68e95 100644
--- a/ui/l10n/pl.js
+++ b/ui/l10n/pl.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Services",
     "label.session.expired": "Session Expired",
     "label.set.default.NIC": "Set default NIC",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Set up zone type",
     "label.settings": "Settings",
     "label.setup": "Konfiguracja",
diff --git a/ui/l10n/pt_BR.js b/ui/l10n/pt_BR.js
index 1b0be1897f4..a6041f3ffb6 100644
--- a/ui/l10n/pt_BR.js
+++ b/ui/l10n/pt_BR.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Servi?os",
     "label.session.expired": "Sess?o Expirada",
     "label.set.default.NIC": "Configurar para NIC padr?o",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "Configurar tipo de zona",
     "label.settings": "Ajustes",
     "label.setup": "Configura??o",
diff --git a/ui/l10n/ru_RU.js b/ui/l10n/ru_RU.js
index 62c2602f6d6..38b78d54452 100644
--- a/ui/l10n/ru_RU.js
+++ b/ui/l10n/ru_RU.js
@@ -1488,6 +1488,8 @@ var dictionary = {
     "label.services": "Services",
     "label.session.expired": "????? ????????",
     "label.set.default.NIC": "?????????? NIC ?? ?????????",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "????????? ??? ????",
     "label.settings": "?????????",
     "label.setup": "?????????",
diff --git a/ui/l10n/zh_CN.js b/ui/l10n/zh_CN.js
index 78729d9a500..9115e94cf0d 100644
--- a/ui/l10n/zh_CN.js
+++ b/ui/l10n/zh_CN.js
@@ -1489,6 +1489,8 @@ var dictionary = {
     "label.services": "??",
     "label.session.expired": "?????",
     "label.set.default.NIC": "???? NIC",
+    "label.set.reservation": "Set reservation",
+    "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
     "label.set.up.zone.type": "???????",
     "label.settings": "??",
     "label.setup": "??",
diff --git a/ui/scripts/docs.js b/ui/scripts/docs.js
index a8ab405d754..d25dca57998 100755
--- a/ui/scripts/docs.js
+++ b/ui/scripts/docs.js
@@ -1340,5 +1340,8 @@ cloudStack.docs = {
     },
     helpLdapLinkDomainAdmin: {
         desc: 'domain admin of the linked domain. Specify a username in GROUP/OU of LDAP'
+    },
+    helpSetReservationSystemVms: {
+        desc: 'If enabled, IP range reservation is set for SSVM & CPVM. Global setting "system.vm.public.ip.reservation.mode.strictness" is used to control whether reservation is strict or not (preferred)'
     }
 };
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index f216423d4bf..38f6074a3d9 100755
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -54,6 +54,12 @@
                 var data = args.data ? args.data: {
                 };
                 var fields = {
+                    systemvms: {
+                        label: 'label.system.vms',
+                        isBoolean: true,
+                        docID: 'helpSetReservationSystemVms',
+                        defaultValue: data.systemvms
+                    },
                     account: {
                         label: 'label.account',
                         defaultValue: data.account
@@ -96,22 +102,40 @@
                         success: function (json) {
                             var domain = json.listdomainsresponse.domain[0];
 
+                            if (data.forSystemVms != null) {
+                                systemvms = '<li>' + _l('label.system.vms') + ': ' + data.forSystemVms + '</li>'
+                            }
                             if (data.account != null)
                                 cloudStack.dialog.notice({
-                                    message: '<ul><li>' + _l('label.account') + ': ' + data.account + '</li>' + '<li>' + _l('label.domain') + ': ' + domain.path + '</li></ul>'
+                                    message: '<ul><li>' + _l('label.account') + ': ' + data.account + '</li>' + '<li>' + _l('label.domain') + ': ' + domain.path + '</li>' + systemvms + '</ul>'
                                 });
                             else
                                 cloudStack.dialog.notice({
-                                    message: '<ul><li>' + _l('label.domain') + ': ' + domain.path + '</li></ul>'
+                                    message: '<ul><li>' + _l('label.domain') + ': ' + domain.path + '</li>' + systemvms + '</ul>'
                                 });
                         }
                     });
                 } else {
                     cloudStack.dialog.createForm({
                         form: {
-                            title: 'label.add.account',
-                            desc: '(optional) Please specify an account to be associated with this IP range.',
-                            fields: fields
+                            title: 'label.set.reservation',
+                            desc: 'label.set.reservation.desc',
+                            fields: fields,
+                            preFilter: function(args) {
+                                var $systemvms = args.$form.find('.form-item[rel=systemvms]');
+                                var $systemvmsCb = $systemvms.find('input[type=checkbox]');
+                                var $account = args.$form.find('.form-item[rel=account]');
+                                var $accountTxt = args.$form.find('input[name=account]');
+                                $systemvmsCb.change(function() {
+                                    if ($systemvmsCb.is(':checked')) {
+                                        $accountTxt.val('');
+                                        $accountTxt.attr('disabled', true);
+                                    }
+                                    else {
+                                        $accountTxt.attr('disabled', false);
+                                    }
+                                });
+                            }
                         },
                         after: function (args) {
                             var data = cloudStack.serializeForm(args.$form);
@@ -438,7 +462,7 @@
                                             'account': {
                                                 label: 'label.account',
                                                 custom: {
-                                                    buttonLabel: 'label.add.account',
+                                                    buttonLabel: 'label.set.reservation',
                                                     action: cloudStack.publicIpRangeAccount.dialog()
                                                 }
                                             },
@@ -466,6 +490,10 @@
                                                 if (args.data.account) {
                                                     if (args.data.account.account)
                                                         array1.push("&account=" + args.data.account.account);
+                                                    if (args.data.account.systemvms) {
+                                                        systvmsval = args.data.account.systemvms == "on" ? "true" : "false"
+                                                        array1.push("&forsystemvms=" + systvmsval);
+                                                    }
                                                     array1.push("&domainid=" + args.data.account.domainid);
                                                 }
 
@@ -627,7 +655,8 @@
                                                                 account: {
                                                                     _buttonLabel: item.account ? '[' + item.domain + '] ' + item.account: item.domain,
                                                                     account: item.account,
-                                                                    domainid: item.domainid
+                                                                    domainid: item.domainid,
+                                                                    forSystemVms: item.forsystemvms
                                                                 }
                                                             });
                                                         })


 

----------------------------------------------------------------
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:
users@infra.apache.org


With regards,
Apache Git Services