You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ya...@apache.org on 2013/10/31 03:30:53 UTC

git commit: updated refs/heads/master to 3205cd4

Updated Branches:
  refs/heads/master 146019649 -> 3205cd42b


CLOUDSTACK-730: Site-to-site VPN between VPC VR to VR

Now VPN connection can be created as "passive", which would enable the ability
of remote peer initiate the connection. So it's possible for VPC VR to
establish the connection to another VPC VR of CloudStack.

Test case also included.

The test case would create 2 vpcs and using VPN to connect them.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/3205cd42
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/3205cd42
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/3205cd42

Branch: refs/heads/master
Commit: 3205cd42b59a4948194c5bd8853b83edec620ba8
Parents: 1460196
Author: Sheng Yang <sh...@citrix.com>
Authored: Wed Oct 30 16:08:33 2013 -0700
Committer: Sheng Yang <sh...@citrix.com>
Committed: Wed Oct 30 19:30:22 2013 -0700

----------------------------------------------------------------------
 .../cloud/network/Site2SiteVpnConnection.java   |   1 +
 .../org/apache/cloudstack/api/ApiConstants.java |   1 +
 .../user/vpn/CreateVpnConnectionCmd.java        |  10 +
 .../Site2SiteVpnConnectionResponse.java         |   7 +
 .../api/routing/Site2SiteVpnCfgCommand.java     |  12 +-
 .../virtualnetwork/VirtualRoutingResource.java  |   3 +
 .../network/dao/Site2SiteVpnConnectionVO.java   |  14 +-
 .../vmware/resource/VmwareResource.java         |   3 +
 .../xen/resource/CitrixResourceBase.java        |   3 +
 server/src/com/cloud/api/ApiResponseHelper.java |   1 +
 .../VpcVirtualNetworkApplianceManagerImpl.java  |   2 +-
 .../network/vpn/Site2SiteVpnManagerImpl.java    |   8 +-
 setup/db/db/schema-421to430.sql                 |   2 +
 .../debian/config/opt/cloud/bin/ipsectunnel.sh  |  47 ++--
 test/integration/smoke/test_vpc_vpn.py          | 229 +++++++++++++++++--
 15 files changed, 304 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/api/src/com/cloud/network/Site2SiteVpnConnection.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/network/Site2SiteVpnConnection.java b/api/src/com/cloud/network/Site2SiteVpnConnection.java
index 810f999..984b051 100644
--- a/api/src/com/cloud/network/Site2SiteVpnConnection.java
+++ b/api/src/com/cloud/network/Site2SiteVpnConnection.java
@@ -35,4 +35,5 @@ public interface Site2SiteVpnConnection extends ControlledEntity, InternalIdenti
     public State getState();
     public Date getCreated();
     public Date getRemoved();
+    public boolean isPassive();
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index e56fdbc..b1bfcfb 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -524,6 +524,7 @@ public class ApiConstants {
     public static final String RESOURCE_DETAILS = "resourcedetails";
     public static final String EXPUNGE = "expunge";
     public static final String FOR_DISPLAY = "fordisplay";
+    public static final String PASSIVE = "passive";
 
     public enum HostDetails {
         all, capacity, events, stats, min;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java
index a8c6dc2..b5cebf36 100644
--- a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnConnectionCmd.java
@@ -53,6 +53,9 @@ public class CreateVpnConnectionCmd extends BaseAsyncCreateCmd {
             required=true, description="id of the customer gateway")
     private Long customerGatewayId;
 
+    @Parameter(name=ApiConstants.PASSIVE, type=CommandType.BOOLEAN, required=false, description="connection is passive or not")
+    private Boolean passive;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -65,6 +68,13 @@ public class CreateVpnConnectionCmd extends BaseAsyncCreateCmd {
     public Long getCustomerGatewayId() {
         return customerGatewayId;
     }
+    
+    public boolean isPassive() {
+    	if (passive == null) {
+    		return false;
+    	}
+    	return passive;
+    }
 
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/api/src/org/apache/cloudstack/api/response/Site2SiteVpnConnectionResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/Site2SiteVpnConnectionResponse.java b/api/src/org/apache/cloudstack/api/response/Site2SiteVpnConnectionResponse.java
index 99075b5..b4cf5e7 100644
--- a/api/src/org/apache/cloudstack/api/response/Site2SiteVpnConnectionResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/Site2SiteVpnConnectionResponse.java
@@ -68,6 +68,9 @@ public class Site2SiteVpnConnectionResponse extends BaseResponse implements Cont
     @SerializedName(ApiConstants.STATE) @Param(description="State of vpn connection")
     private String state;
 
+    @SerializedName(ApiConstants.PASSIVE) @Param(description="State of vpn connection")
+    private boolean passive;
+
     @SerializedName(ApiConstants.ACCOUNT) @Param(description="the owner")
     private String accountName;
 
@@ -141,6 +144,10 @@ public class Site2SiteVpnConnectionResponse extends BaseResponse implements Cont
         this.state = state;
     }
 
+	public void setPassive(boolean passive) {
+		this.passive = passive;
+	}
+
     public void setCreated(Date created) {
         this.created = created;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/core/src/com/cloud/agent/api/routing/Site2SiteVpnCfgCommand.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/api/routing/Site2SiteVpnCfgCommand.java b/core/src/com/cloud/agent/api/routing/Site2SiteVpnCfgCommand.java
index 8316303..d54c29c 100644
--- a/core/src/com/cloud/agent/api/routing/Site2SiteVpnCfgCommand.java
+++ b/core/src/com/cloud/agent/api/routing/Site2SiteVpnCfgCommand.java
@@ -30,6 +30,7 @@ public class Site2SiteVpnCfgCommand extends NetworkElementCommand {
     private long ikeLifetime;
     private long espLifetime;
     private boolean dpd;
+    private boolean passive;
 
 	@Override
     public boolean executeInSequence() {
@@ -41,7 +42,7 @@ public class Site2SiteVpnCfgCommand extends NetworkElementCommand {
     }
 
     public Site2SiteVpnCfgCommand (boolean create, String localPublicIp, String localPublicGateway, String localGuestCidr, String peerGatewayIp,
-            String peerGuestCidrList, String ikePolicy, String espPolicy, String ipsecPsk, Long ikeLifetime, Long espLifetime, Boolean dpd) {
+            String peerGuestCidrList, String ikePolicy, String espPolicy, String ipsecPsk, Long ikeLifetime, Long espLifetime, Boolean dpd, boolean passive) {
         this.create = create;
         this.setLocalPublicIp(localPublicIp);
         this.setLocalPublicGateway(localPublicGateway);
@@ -54,6 +55,7 @@ public class Site2SiteVpnCfgCommand extends NetworkElementCommand {
         this.ikeLifetime = ikeLifetime;
         this.espLifetime = espLifetime;
         this.dpd = dpd;
+        this.passive = passive;
     }
 
     public boolean isCreate() {
@@ -151,4 +153,12 @@ public class Site2SiteVpnCfgCommand extends NetworkElementCommand {
     public void setPeerGuestCidrList(String peerGuestCidrList) {
         this.peerGuestCidrList = peerGuestCidrList;
     }
+
+	public boolean isPassive() {
+		return passive;
+	}
+
+	public void setPassive(boolean passive) {
+		this.passive = passive;
+	}
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java
index 874146c..4c2ee50 100755
--- a/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java
+++ b/core/src/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java
@@ -761,6 +761,9 @@ public class VirtualRoutingResource implements Manager {
             } else {
                 args += "0";
             }
+            if (cmd.isPassive()) {
+            	args += " -p ";
+            }
         } else {
             args = "-D";
             args += " -r ";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionVO.java b/engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionVO.java
index f8eeb8a..d99823f 100644
--- a/engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionVO.java
+++ b/engine/schema/src/com/cloud/network/dao/Site2SiteVpnConnectionVO.java
@@ -66,15 +66,19 @@ public class Site2SiteVpnConnectionVO implements Site2SiteVpnConnection, Interna
     @Column(name=GenericDao.REMOVED_COLUMN)
     private Date removed;
     
+    @Column(name="passive")
+    private boolean passive;
+
     public Site2SiteVpnConnectionVO() { }
 
-    public Site2SiteVpnConnectionVO(long accountId, long domainId, long vpnGatewayId, long customerGatewayId) {
+    public Site2SiteVpnConnectionVO(long accountId, long domainId, long vpnGatewayId, long customerGatewayId, boolean passive) {
         this.uuid = UUID.randomUUID().toString();
         this.setVpnGatewayId(vpnGatewayId);
         this.setCustomerGatewayId(customerGatewayId);
         this.setState(State.Pending);
         this.accountId = accountId;
         this.domainId = domainId;
+        this.passive = passive;
     }
     
     @Override
@@ -140,4 +144,12 @@ public class Site2SiteVpnConnectionVO implements Site2SiteVpnConnection, Interna
     public long getAccountId() {
         return accountId;
     }
+
+	public boolean isPassive() {
+		return passive;
+	}
+
+	public void setPassive(boolean passive) {
+		this.passive = passive;
+	}
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 423abe6..6d3d34a 100755
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -1559,6 +1559,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             } else {
                 args += "0";
             }
+            if (cmd.isPassive()) {
+            	args += " -p ";
+            }
         } else {
             args += " -D";
             args += " -r ";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index 3323a15..3df28ed 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -8519,6 +8519,9 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             } else {
                 args += "0";
             }
+            if (cmd.isPassive()) {
+            	args += " -p ";
+            }
         } else {
             args += " -D";
             args += " -r ";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index de4cc66..769d345 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -3195,6 +3195,7 @@ public class ApiResponseHelper implements ResponseGenerator {
     public Site2SiteVpnConnectionResponse createSite2SiteVpnConnectionResponse(Site2SiteVpnConnection result) {
         Site2SiteVpnConnectionResponse response = new Site2SiteVpnConnectionResponse();
         response.setId(result.getUuid());
+        response.setPassive(result.isPassive());
 
         Long vpnGatewayId = result.getVpnGatewayId();
         if (vpnGatewayId != null) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
index 63eb75b..ecfce57 100644
--- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
+++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java
@@ -1122,7 +1122,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian
         Boolean dpd = gw.getDpd();
 
         Site2SiteVpnCfgCommand cmd = new Site2SiteVpnCfgCommand(isCreate, localPublicIp, localPublicGateway, localGuestCidr,
-                peerGatewayIp, peerGuestCidrList, ikePolicy, espPolicy, ipsecPsk, ikeLifetime, espLifetime, dpd);
+                peerGatewayIp, peerGuestCidrList, ikePolicy, espPolicy, ipsecPsk, ikeLifetime, espLifetime, dpd, conn.isPassive());
         cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId()));
         cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId()));
         cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java b/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
index f29a8c8..94d2dc3 100644
--- a/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
+++ b/server/src/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
@@ -290,7 +290,7 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
             }
         }
 
-        Site2SiteVpnConnectionVO conn = new Site2SiteVpnConnectionVO(owner.getAccountId(), owner.getDomainId(), vpnGatewayId, customerGatewayId);
+        Site2SiteVpnConnectionVO conn = new Site2SiteVpnConnectionVO(owner.getAccountId(), owner.getDomainId(), vpnGatewayId, customerGatewayId, cmd.isPassive());
         conn.setState(State.Pending);
         _vpnConnectionDao.persist(conn);
         return conn;
@@ -317,7 +317,11 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
             }
 
             if (result) {
-                conn.setState(State.Connected);
+            	if (conn.isPassive()) {
+            		conn.setState(State.Disconnected);
+            	} else {
+            		conn.setState(State.Connected);
+            	}
                 _vpnConnectionDao.persist(conn);
                 return conn;
             }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/setup/db/db/schema-421to430.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-421to430.sql b/setup/db/db/schema-421to430.sql
index 803f1d9..0de9dfd 100644
--- a/setup/db/db/schema-421to430.sql
+++ b/setup/db/db/schema-421to430.sql
@@ -119,6 +119,8 @@ UPDATE `cloud`.`vm_template` SET `removed`=NULL;
 ALTER TABLE `cloud`.`remote_access_vpn` MODIFY COLUMN `network_id` bigint unsigned;
 ALTER TABLE `cloud`.`remote_access_vpn` ADD COLUMN `vpc_id` bigint unsigned default NULL;
 
+ALTER TABLE `cloud`.`s2s_vpn_connection` ADD COLUMN `passive` int(1) unsigned NOT NULL DEFAULT 0;
+
 DROP VIEW IF EXISTS `cloud`.`disk_offering_view`;
 CREATE VIEW `cloud`.`disk_offering_view` AS
     select

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/systemvm/patches/debian/config/opt/cloud/bin/ipsectunnel.sh
----------------------------------------------------------------------
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/ipsectunnel.sh b/systemvm/patches/debian/config/opt/cloud/bin/ipsectunnel.sh
index e511a3d..e20c10f 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/ipsectunnel.sh
+++ b/systemvm/patches/debian/config/opt/cloud/bin/ipsectunnel.sh
@@ -30,7 +30,7 @@ vpnoutmark="0x525"
 vpninmark="0x524"
 
 usage() {
-    printf "Usage: %s: (-A|-D) -l <left-side vpn peer> -n <left-side guest cidr> -g <left-side gateway> -r <right-side vpn peer> -N <right-side private subnets> -e <esp policy> -i <ike policy> -t <ike lifetime> -T <esp lifetime> -s <pre-shared secret> -d <dpd 0 or 1> \n" $(basename $0) >&2
+    printf "Usage: %s: (-A|-D) -l <left-side vpn peer> -n <left-side guest cidr> -g <left-side gateway> -r <right-side vpn peer> -N <right-side private subnets> -e <esp policy> -i <ike policy> -t <ike lifetime> -T <esp lifetime> -s <pre-shared secret> -d <dpd 0 or 1> [ -p <passive or not> ]\n" $(basename $0) >&2
 }
 
 #set -x
@@ -173,29 +173,35 @@ ipsec_tunnel_add() {
 
     sudo ipsec auto --rereadall
     sudo ipsec auto --add vpn-$rightpeer
-    sudo ipsec auto --up vpn-$rightpeer
 
   logger -t cloud "$(basename $0): done ipsec tunnel entry for right peer=$rightpeer right networks=$rightnets"
 
-  #5 seconds for checking if it's ready
-  for i in {1..5}
-  do
-    logger -t cloud "$(basename $0): checking connection status..."
-    /opt/cloud/bin/checks2svpn.sh $rightpeer
-    result=$?
+  result=0
+
+  if [ $passive -eq 0 ]
+  then
+      sudo ipsec auto --up vpn-$rightpeer
+
+    #5 seconds for checking if it's ready
+    for i in {1..5}
+    do
+      logger -t cloud "$(basename $0): checking connection status..."
+      /opt/cloud/bin/checks2svpn.sh $rightpeer
+      result=$?
+      if [ $result -eq 0 ]
+      then
+          break
+      fi
+      sleep 1
+    done
     if [ $result -eq 0 ]
     then
-        break
+      logger -t cloud "$(basename $0): connect to remote successful"
+    else
+      logger -t cloud "$(basename $0): fail to connect to remote, status code: $result"
+      logger -t cloud "$(basename $0): would stop site-to-site VPN connection"
+      ipsec_tunnel_del
     fi
-    sleep 1
-  done
-  if [ $result -eq 0 ]
-  then
-    logger -t cloud "$(basename $0): connect to remote successful"
-  else
-    logger -t cloud "$(basename $0): fail to connect to remote, status code: $result"
-    logger -t cloud "$(basename $0): would stop site-to-site VPN connection"
-    ipsec_tunnel_del
   fi
   return $result
 }
@@ -208,9 +214,10 @@ lflag=
 iflag=
 Iflag=
 sflag=
+passive=0
 op=""
 
-while getopts 'ADl:n:g:r:N:e:i:t:T:s:d:' OPTION
+while getopts 'ADpl:n:g:r:N:e:i:t:T:s:d:' OPTION
 do
   case $OPTION in
   A)    opflag=1
@@ -252,6 +259,8 @@ do
   d)    dflag=1
         dpd="$OPTARG"
         ;;
+  p)    passive=1
+        ;;
   ?)    usage
         unlock_exit 2 $lock $locked
         ;;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3205cd42/test/integration/smoke/test_vpc_vpn.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_vpc_vpn.py b/test/integration/smoke/test_vpc_vpn.py
index c360884..5e97c79 100644
--- a/test/integration/smoke/test_vpc_vpn.py
+++ b/test/integration/smoke/test_vpc_vpn.py
@@ -24,6 +24,8 @@ from marvin.integration.lib.base import *
 from marvin.integration.lib.common import *
 from nose.plugins.attrib import attr
 
+import time
+
 class Services:
     def __init__(self):
         self.services = {
@@ -77,15 +79,37 @@ class Services:
             "vpn_user": {
                 "username": "test",
                 "password": "password",
+            },
+            "vpc": {
+                "name": "vpc_vpn",
+                "displaytext": "vpc-vpn",
+                "cidr": "10.1.1.0/24"
+            },
+            "ntwk": {
+                "name": "tier1",
+                "displaytext": "vpc-tier1",
+                "gateway" : "10.1.1.1",
+                "netmask" : "255.255.255.192"
+            },
+            "vpc2": {
+                "name": "vpc2_vpn",
+                "displaytext": "vpc2-vpn",
+                "cidr": "10.2.1.0/24"
+            },
+            "ntwk2": {
+                "name": "tier2",
+                "displaytext": "vpc-tier2",
+                "gateway" : "10.2.1.1",
+                "netmask" : "255.255.255.192"
             }
         }
 
 
-class TestVpcVpn(cloudstackTestCase):
+class TestVpcRemoteAccessVpn(cloudstackTestCase):
 
     @classmethod
     def setUpClass(cls):
-        cls.apiclient = super(TestVpcVpn, cls).getClsTestClient().getApiClient()
+        cls.apiclient = super(TestVpcRemoteAccessVpn, cls).getClsTestClient().getApiClient()
         cls.services = Services().services
         cls.zone = get_zone(cls.apiclient, cls.services)
         cls.domain = get_domain(cls.apiclient)
@@ -102,7 +126,7 @@ class TestVpcVpn(cloudstackTestCase):
         cls.cleanup = [cls.account]
 
     @attr(tags=["advanced"])
-    def test_vpc_vpn(self):
+    def test_vpc_remote_access_vpn(self):
         """Test VPN in VPC"""
 
         # 0) Get the default network offering for VPC
@@ -112,10 +136,6 @@ class TestVpcVpn(cloudstackTestCase):
         # 1) Create VPC
         vpcOffering = VpcOffering.list(self.apiclient,isdefault=True)
         self.assert_(vpcOffering is not None and len(vpcOffering)>0, "No VPC offerings found")
-        self.services["vpc"] = {}
-        self.services["vpc"]["name"] = "vpc-vpn"
-        self.services["vpc"]["displaytext"] = "vpc-vpn"
-        self.services["vpc"]["cidr"] = "10.1.1.0/24"
         vpc = VPC.create(
                 apiclient=self.apiclient,
                 services=self.services["vpc"],
@@ -126,33 +146,29 @@ class TestVpcVpn(cloudstackTestCase):
                 domainid=self.domain.id
         )
         self.assert_(vpc is not None, "VPC creation failed")
+        self.debug("VPC %s created" %(vpc.id))
 
         # 2) Create network in VPC
-        self.services["vpcnetwork"] = {}
-        self.services["vpcnetwork"]["name"] = "vpcntwk"
-        self.services["vpcnetwork"]["displaytext"] = "vpcntwk"
         ntwk = Network.create(
             apiclient=self.apiclient,
-            services=self.services["vpcnetwork"],
+            services=self.services["ntwk"],
             accountid=self.account.name,
             domainid=self.domain.id,
             networkofferingid=networkOffering[0].id,
             zoneid=self.zone.id,
-            vpcid=vpc.id,
-            gateway="10.1.1.1",
-            netmask="255.255.255.192"
+            vpcid=vpc.id
         )
         self.assertIsNotNone(ntwk, "Network failed to create")
         self.debug("Network %s created in VPC %s" %(ntwk.id, vpc.id))
 
         # 3) Deploy a vm
-        self.services["virtual_machine"]["networkids"] = ntwk.id
         vm = VirtualMachine.create(self.apiclient, services=self.services["virtual_machine"],
             templateid=self.template.id,
             zoneid=self.zone.id,
             accountid=self.account.name,
             domainid= self.domain.id,
             serviceofferingid=self.service_offering.id,
+            networkids=ntwk.id
         )
         self.assert_(vm is not None, "VM failed to deploy")
         self.assert_(vm.state == 'Running', "VM is not running")
@@ -190,3 +206,186 @@ class TestVpcVpn(cloudstackTestCase):
             cleanup_resources(cls.apiclient, cls.cleanup)
         except Exception, e:
             raise Exception("Cleanup failed with %s" % e)
+
+class TestVpcSite2SiteVpn(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.apiclient = super(TestVpcSite2SiteVpn, cls).getClsTestClient().getApiClient()
+        cls.services = Services().services
+        cls.zone = get_zone(cls.apiclient, cls.services)
+        cls.domain = get_domain(cls.apiclient)
+        cls.service_offering = ServiceOffering.create(
+            cls.apiclient,
+            cls.services["service_offering"]
+        )
+        cls.account = Account.create(cls.apiclient, services=cls.services["account"])
+        cls.template = get_template(
+            cls.apiclient,
+            cls.zone.id,
+            cls.services["ostype"]
+        )
+        cls.cleanup = [cls.account]
+
+    @attr(tags=["advanced"])
+    def test_vpc_site2site_vpn(self):
+        """Test VPN in VPC"""
+
+        # 0) Get the default network offering for VPC
+        networkOffering = NetworkOffering.list(self.apiclient, name="DefaultIsolatedNetworkOfferingForVpcNetworks")
+        self.assert_(networkOffering is not None and len(networkOffering) > 0, "No VPC based network offering")
+
+        # 1) Create VPC
+        vpcOffering = VpcOffering.list(self.apiclient,isdefault=True)
+        self.assert_(vpcOffering is not None and len(vpcOffering)>0, "No VPC offerings found")
+
+        vpc1 = VPC.create(
+                apiclient=self.apiclient,
+                services=self.services["vpc"],
+                networkDomain="vpc1.vpn",
+                vpcofferingid=vpcOffering[0].id,
+                zoneid=self.zone.id,
+                account=self.account.name,
+                domainid=self.domain.id
+        )
+        self.assert_(vpc1 is not None, "VPC creation failed")
+        self.debug("VPC1 %s created" %(vpc1.id))
+
+        vpc2 = VPC.create(
+                apiclient=self.apiclient,
+                services=self.services["vpc2"],
+                networkDomain="vpc2.vpn",
+                vpcofferingid=vpcOffering[0].id,
+                zoneid=self.zone.id,
+                account=self.account.name,
+                domainid=self.domain.id
+        )
+        self.assert_(vpc2 is not None, "VPC2 creation failed")
+        self.debug("VPC2 %s created" %(vpc1.id))
+
+        # 2) Create network in VPC
+        ntwk1 = Network.create(
+            apiclient=self.apiclient,
+            services=self.services["ntwk"],
+            accountid=self.account.name,
+            domainid=self.domain.id,
+            networkofferingid=networkOffering[0].id,
+            zoneid=self.zone.id,
+            vpcid=vpc1.id
+        )
+        self.assertIsNotNone(ntwk1, "Network failed to create")
+        self.debug("Network %s created in VPC %s" %(ntwk1.id, vpc1.id))
+
+        ntwk2 = Network.create(
+            apiclient=self.apiclient,
+            services=self.services["ntwk2"],
+            accountid=self.account.name,
+            domainid=self.domain.id,
+            networkofferingid=networkOffering[0].id,
+            zoneid=self.zone.id,
+            vpcid=vpc2.id
+        )
+        self.assertIsNotNone(ntwk2, "Network failed to create")
+        self.debug("Network %s created in VPC %s" %(ntwk2.id, vpc2.id))
+
+        # 3) Deploy a vm
+        vm1 = VirtualMachine.create(self.apiclient, services=self.services["virtual_machine"],
+            templateid=self.template.id,
+            zoneid=self.zone.id,
+            accountid=self.account.name,
+            domainid= self.domain.id,
+            serviceofferingid=self.service_offering.id,
+            networkids=ntwk1.id
+        )
+        self.assert_(vm1 is not None, "VM failed to deploy")
+        self.assert_(vm1.state == 'Running', "VM is not running")
+        self.debug("VM %s deployed in VPC %s" %(vm1.id, vpc1.id))
+
+        vm2 = VirtualMachine.create(self.apiclient, services=self.services["virtual_machine"],
+            templateid=self.template.id,
+            zoneid=self.zone.id,
+            accountid=self.account.name,
+            domainid= self.domain.id,
+            serviceofferingid=self.service_offering.id,
+            networkids=ntwk2.id
+        )
+        self.assert_(vm2 is not None, "VM failed to deploy")
+        self.assert_(vm2.state == 'Running', "VM is not running")
+        self.debug("VM %s deployed in VPC %s" %(vm2.id, vpc2.id))
+
+        # 4) Enable Site-to-Site VPN for VPC
+        cmd=createVpnGateway.createVpnGatewayCmd()
+        cmd.vpcid=vpc1.id
+        vpn1_response = self.apiclient.createVpnGateway(cmd)
+
+        self.debug("VPN gateway for VPC %s enabled" % (vpc1.id))
+
+        cmd=createVpnGateway.createVpnGatewayCmd()
+        cmd.vpcid=vpc2.id
+        vpn2_response = self.apiclient.createVpnGateway(cmd)
+
+        self.debug("VPN gateway for VPC %s enabled" %(vpc2.id))
+
+        # 5) Add VPN Customer gateway info
+
+        src_nat_list = PublicIPAddress.list(
+                                        self.apiclient,
+                                        account=self.account.name,
+                                        domainid=self.account.domainid,
+                                        listall=True,
+                                        issourcenat=True,
+                                        vpcid=vpc1.id
+                                        )
+        ip1 = src_nat_list[0]
+
+        src_nat_list = PublicIPAddress.list(
+                                        self.apiclient,
+                                        account=self.account.name,
+                                        domainid=self.account.domainid,
+                                        listall=True,
+                                        issourcenat=True,
+                                        vpcid=vpc2.id
+                                        )
+        ip2 = src_nat_list[0]
+
+        cmd=createVpnCustomerGateway.createVpnCustomerGatewayCmd()
+        cmd.esppolicy="3des-md5;modp1536"
+        cmd.ikepolicy="3des-md5;modp1536"
+        cmd.domainid=self.account.domainid
+        cmd.account=self.account.name
+        cmd.ipsecpsk="ipsecpsk"
+
+        cmd.name="Peer VPC1"
+        cmd.gateway=ip1.ipaddress
+        cmd.cidrlist=vpc1.cidr
+        customer1_response = self.apiclient.createVpnCustomerGateway(cmd)
+        self.debug("VPN customer gateway added for VPC %s enabled" %(vpc1.id))
+
+        cmd.name="Peer VPC2"
+        cmd.gateway=ip2.ipaddress
+        cmd.cidrlist=vpc2.cidr
+        customer2_response = self.apiclient.createVpnCustomerGateway(cmd)
+        self.debug("VPN customer gateway added for VPC %s enabled" %(vpc2.id))
+
+        # 6) Connect two VPCs 
+        cmd = createVpnConnection.createVpnConnectionCmd()
+        cmd.s2svpngatewayid = vpn2_response.id
+        cmd.s2scustomergatewayid = customer1_response.id
+        cmd.passive="true"
+        vpnconn1_response = self.apiclient.createVpnConnection(cmd)
+        self.debug("VPN passive connection created for VPC %s" %(vpc2.id))
+
+        cmd = createVpnConnection.createVpnConnectionCmd()
+        cmd.s2svpngatewayid = vpn1_response.id
+        cmd.s2scustomergatewayid = customer2_response.id
+        vpnconn2_response = self.apiclient.createVpnConnection(cmd)
+        self.debug("VPN connection created for VPC %s" %(vpc1.id))
+
+        self.assertEqual(vpnconn2_response.state, "Connected", "Failed to connect between VPCs!")
+
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            cleanup_resources(cls.apiclient, cls.cleanup)
+        except Exception, e:
+            raise Exception("Cleanup failed with %s" % e)