You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by sa...@apache.org on 2013/05/22 15:56:53 UTC
[10/50] [abbrv] git commit: updated refs/heads/vmware-datamodel to
8996ea3
CLOUDSTACK-652: meging 'portable public ip' feature
Squashed commit of the following:
commit f244f9ce7982db16984dd87c31545f1c0240c704
Merge: 993cbb0 f5c8e38
Author: Murali Reddy <mu...@gmail.com>
Date: Mon May 20 18:54:05 2013 +0530
Merge branch 'master' into portablepublicip
Conflicts:
server/src/com/cloud/server/ManagementServerImpl.java
server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
commit 993cbb0df9fa6e64b96b18ed775b73cdf4a8f5d7
Author: Murali Reddy <mu...@gmail.com>
Date: Mon May 20 18:49:54 2013 +0530
introduce 'transferPortableIP' interface method in network manger. This
method will transfer association of portable ip from one network to
another network.
commit 0c1c2652c1b39e9a81ca35464360e11ed9ef23f1
Merge: a718d35 a29e393
Author: Murali Reddy <mu...@gmail.com>
Date: Fri May 17 02:48:54 2013 +0530
Merge branch 'master' into portablepublicip
Conflicts:
utils/src/com/cloud/utils/net/NetUtils.java
commit a718d353f7acf0328d928673df6f22de1abc0acb
Merge: ecca117 c211818
Author: Murali Reddy <mu...@gmail.com>
Date: Mon May 13 21:22:19 2013 +0530
Merge branch 'master' into portablepublicip
Conflicts:
api/src/org/apache/cloudstack/api/ResponseGenerator.java
server/src/com/cloud/api/ApiResponseHelper.java
server/src/com/cloud/network/NetworkServiceImpl.java
server/src/com/cloud/network/addr/PublicIp.java
server/src/com/cloud/server/ManagementServerImpl.java
server/test/com/cloud/network/MockNetworkManagerImpl.java
server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
server/test/com/cloud/vpc/MockNetworkManagerImpl.java
setup/db/db/schema-410to420.sql
commit ecca117e345224059297f5c1ffa0f442209b3160
Author: Murali Reddy <mu...@gmail.com>
Date: Mon May 13 20:05:29 2013 +0530
added integration tests for testing portable ip ranges
commit 895a27c2771dbb497ecc6fe0d212589f012a48d8
Author: Murali Reddy <mu...@gmail.com>
Date: Mon May 13 15:12:19 2013 +0530
- establish model for transferring portable IP association from a network
with which it is associated to another network.
- enabling static nat api, extended to transfer potrtable IP across the
networks if the VM/network is different from the current associate
network of the portable ip
commit 51509751b290c0e51cbdd104a9aebff189cbe806
Author: Murali Reddy <mu...@gmail.com>
Date: Mon May 13 12:05:33 2013 +0530
seperate out associate/disassociate with guest network operations from
alloc and release of portable ip
commit bd058f58c2d8d36ec25e31ed9de4cd414e0ca051
Author: Murali Reddy <mu...@gmail.com>
Date: Sun May 12 21:14:48 2013 +0530
enhance disasociateIPAddr API to release protable IP associated with a
guest network or VPC
commit 27504d9098729e8c3ac3b33f053f2d66ac2c4401
Author: Murali Reddy <mu...@gmail.com>
Date: Sun May 12 16:53:45 2013 +0530
enhance asociateIPAddr API to acquire a protable IP and associate with a
guest network or VPC
commit f82c6a8431647114462665c1306c6215cb92afd3
Merge: 3dbfb44 0749013
Author: Murali Reddy <mu...@gmail.com>
Date: Sat May 11 23:32:13 2013 +0530
Merge branch 'master' into portablepublicip
Conflicts:
api/src/com/cloud/network/IpAddress.java
api/src/org/apache/cloudstack/api/ResponseGenerator.java
client/tomcatconf/commands.properties.in
server/src/com/cloud/api/ApiResponseHelper.java
server/src/com/cloud/configuration/ConfigurationManagerImpl.java
server/src/com/cloud/server/ManagementServerImpl.java
server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java
server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
setup/db/db/schema-410to420.sql
commit 3dbfb44eb5b888367375a96b8ae0ac9cf54309a6
Author: Murali Reddy <mu...@gmail.com>
Date: Sat May 11 20:33:19 2013 +0530
- add 'portable' boolean as property of IpAddress, persist the property in
IPAddressVO, return the property in IpAddressResponse
- add ability to request portable IP in associateIpAddress api
commit bf3cb274cfeb1ef41c63794ced83c7c6940f34cc
Author: Murali Reddy <mu...@gmail.com>
Date: Sat May 11 16:08:40 2013 +0530
add the status of each portable IP (its state, details of associated data
center/VPC/guest network etc) in the PortableIpRangeResponse returned by
listPortableIpRanges API
commit e7b2fb22557cb4ef0ce9c8dde3ed1b9c857038bf
Author: Murali Reddy <mu...@gmail.com>
Date: Sat May 11 14:36:01 2013 +0530
Introdcues notion of 'portable IP' pool at region level.
Introduces root admin only API's to provision portable ip to a region
- createPortableIpRange
- deletePortableIpRange
- listPortableIpRanges
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/d6452be8
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/d6452be8
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/d6452be8
Branch: refs/heads/vmware-datamodel
Commit: d6452be8618198454c6f20f4210f6ac18ce9b11d
Parents: f5c8e38
Author: Murali Reddy <mu...@gmail.com>
Authored: Mon May 20 20:05:47 2013 +0530
Committer: Murali Reddy <mu...@gmail.com>
Committed: Mon May 20 20:05:47 2013 +0530
----------------------------------------------------------------------
api/src/com/cloud/async/AsyncJob.java | 1 +
.../cloud/configuration/ConfigurationService.java | 13 +
api/src/com/cloud/event/EventTypes.java | 5 +
api/src/com/cloud/network/IpAddress.java | 4 +-
api/src/com/cloud/network/NetworkService.java | 5 +
.../org/apache/cloudstack/api/ApiConstants.java | 2 +
.../apache/cloudstack/api/ResponseGenerator.java | 9 +-
.../admin/region/CreatePortableIpRangeCmd.java | 156 +++++++++
.../admin/region/DeletePortableIpRangeCmd.java | 93 +++++
.../admin/region/ListPortableIpRangesCmd.java | 109 ++++++
.../command/user/address/AssociateIPAddrCmd.java | 28 ++-
.../user/address/DisassociateIPAddrCmd.java | 12 +-
.../api/command/user/nat/EnableStaticNatCmd.java | 6 +
.../cloudstack/api/response/IPAddressResponse.java | 7 +
.../api/response/PortableIpRangeResponse.java | 93 +++++
.../api/response/PortableIpResponse.java | 106 ++++++
.../org/apache/cloudstack/region/PortableIp.java | 58 ++++
.../apache/cloudstack/region/PortableIpRange.java | 38 ++
client/tomcatconf/applicationContext.xml.in | 2 +
client/tomcatconf/commands.properties.in | 6 +
.../src/com/cloud/network/dao/IPAddressVO.java | 24 ++
server/src/com/cloud/api/ApiResponseHelper.java | 70 ++++-
.../configuration/ConfigurationManagerImpl.java | 165 +++++++++-
server/src/com/cloud/network/NetworkManager.java | 14 +
.../src/com/cloud/network/NetworkManagerImpl.java | 262 ++++++++++++++-
.../src/com/cloud/network/NetworkServiceImpl.java | 105 ++++--
server/src/com/cloud/network/addr/PublicIp.java | 9 +
.../com/cloud/network/rules/RulesManagerImpl.java | 43 +++
.../src/com/cloud/server/ManagementServerImpl.java | 86 +++++-
.../apache/cloudstack/region/PortableIpDao.java | 39 +++
.../cloudstack/region/PortableIpDaoImpl.java | 131 +++++++
.../cloudstack/region/PortableIpRangeDao.java | 30 ++
.../cloudstack/region/PortableIpRangeDaoImpl.java | 65 ++++
.../cloudstack/region/PortableIpRangeVO.java | 119 +++++++
.../org/apache/cloudstack/region/PortableIpVO.java | 222 ++++++++++++
.../com/cloud/network/MockNetworkManagerImpl.java | 40 ++-
.../cloud/vpc/MockConfigurationManagerImpl.java | 58 ++++
.../test/com/cloud/vpc/MockNetworkManagerImpl.java | 41 ++-
.../networkoffering/ChildTestConfiguration.java | 7 +
setup/db/db/schema-410to420.sql | 37 ++
test/integration/smoke/test_portable_publicip.py | 237 +++++++++++++
tools/marvin/marvin/integration/lib/base.py | 36 ++
utils/src/com/cloud/utils/net/NetUtils.java | 13 +
43 files changed, 2542 insertions(+), 64 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/com/cloud/async/AsyncJob.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/async/AsyncJob.java b/api/src/com/cloud/async/AsyncJob.java
index ccdc406..47f9b57 100644
--- a/api/src/com/cloud/async/AsyncJob.java
+++ b/api/src/com/cloud/async/AsyncJob.java
@@ -35,6 +35,7 @@ public interface AsyncJob extends Identity, InternalIdentity {
Host,
StoragePool,
IpAddress,
+ PortableIpAddress,
SecurityGroup,
PhysicalNetwork,
TrafficType,
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/com/cloud/configuration/ConfigurationService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/configuration/ConfigurationService.java b/api/src/com/cloud/configuration/ConfigurationService.java
index fdbd9d6..381fcad 100644
--- a/api/src/com/cloud/configuration/ConfigurationService.java
+++ b/api/src/com/cloud/configuration/ConfigurationService.java
@@ -39,6 +39,9 @@ import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd;
import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd;
import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd;
import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd;
+import org.apache.cloudstack.api.command.admin.region.CreatePortableIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.region.DeletePortableIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.region.ListPortableIpRangesCmd;
import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd;
import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd;
import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd;
@@ -56,6 +59,8 @@ import com.cloud.offering.DiskOffering;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.user.Account;
+import org.apache.cloudstack.region.PortableIp;
+import org.apache.cloudstack.region.PortableIpRange;
public interface ConfigurationService {
@@ -278,4 +283,12 @@ public interface ConfigurationService {
* @return
*/
boolean isOfferingForVpc(NetworkOffering offering);
+
+ PortableIpRange createPortableIpRange(CreatePortableIpRangeCmd cmd) throws ConcurrentOperationException;
+
+ boolean deletePortableIpRange(DeletePortableIpRangeCmd cmd);
+
+ List<? extends PortableIpRange> listPortableIpRanges(ListPortableIpRangesCmd cmd);
+
+ List<? extends PortableIp> listPortableIps(long id);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/com/cloud/event/EventTypes.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index 9c83f13..fcac8e8 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -102,6 +102,8 @@ public class EventTypes {
// Network Events
public static final String EVENT_NET_IP_ASSIGN = "NET.IPASSIGN";
public static final String EVENT_NET_IP_RELEASE = "NET.IPRELEASE";
+ public static final String EVENT_PORTABLE_IP_ASSIGN = "PORTABLE.IPASSIGN";
+ public static final String EVENT_PORTABLE_IP_RELEASE = "PORTABLEIPRELEASE";
public static final String EVENT_NET_RULE_ADD = "NET.RULEADD";
public static final String EVENT_NET_RULE_DELETE = "NET.RULEDELETE";
public static final String EVENT_NET_RULE_MODIFY = "NET.RULEMODIFY";
@@ -432,6 +434,9 @@ public class EventTypes {
public static final String EVENT_DEDICATED_GUEST_VLAN_RANGE_RELEASE = "GUESTVLANRANGE.RELEASE";
+ public static final String EVENT_PORTABLE_IP_RANGE_CREATE = "PORTABLE.IP.RANGE.CREATE";
+ public static final String EVENT_PORTABLE_IP_RANGE_DELETE = "PORTABLE.IP.RANGE.DELETE";
+
static {
// TODO: need a way to force author adding event types to declare the entity details as well, with out braking
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/com/cloud/network/IpAddress.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/network/IpAddress.java b/api/src/com/cloud/network/IpAddress.java
index c48e8b9..de11a6d 100644
--- a/api/src/com/cloud/network/IpAddress.java
+++ b/api/src/com/cloud/network/IpAddress.java
@@ -81,7 +81,9 @@ public interface IpAddress extends ControlledEntity, Identity, InternalIdentity
Long getVpcId();
String getVmIp();
-
+
+ boolean isPortable();
+
Long getNetworkId();
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/com/cloud/network/NetworkService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java
index 2e50c53..59702a2 100755
--- a/api/src/com/cloud/network/NetworkService.java
+++ b/api/src/com/cloud/network/NetworkService.java
@@ -52,6 +52,11 @@ public interface NetworkService {
boolean releaseIpAddress(long ipAddressId) throws InsufficientAddressCapacityException;
+ IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long networkId, Long vpcId) throws ResourceAllocationException,
+ InsufficientAddressCapacityException, ConcurrentOperationException;
+
+ boolean releasePortableIpAddress(long ipAddressId) throws InsufficientAddressCapacityException;
+
Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException,
ResourceAllocationException;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/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 cf093bf..1e9435f 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -114,6 +114,7 @@ public class ApiConstants {
public static final String IS_CLEANUP_REQUIRED = "iscleanuprequired";
public static final String IS_EXTRACTABLE = "isextractable";
public static final String IS_FEATURED = "isfeatured";
+ public static final String IS_PORTABLE = "isportable";
public static final String IS_PUBLIC = "ispublic";
public static final String IS_PERSISTENT = "ispersistent";
public static final String IS_READY = "isready";
@@ -158,6 +159,7 @@ public class ApiConstants {
public static final String POLICY_ID = "policyid";
public static final String PORT = "port";
public static final String PORTAL = "portal";
+ public static final String PORTABLE_IP_ADDRESS = "portableipaddress";
public static final String PORT_FORWARDING_SERVICE_ID = "portforwardingserviceid";
public static final String PRIVATE_INTERFACE = "privateinterface";
public static final String PRIVATE_IP = "privateip";
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/api/ResponseGenerator.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
index 10bf305..0732e77 100644
--- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java
+++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
@@ -119,6 +119,8 @@ import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.api.response.*;
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule;
import org.apache.cloudstack.region.Region;
+import org.apache.cloudstack.region.PortableIp;
+import org.apache.cloudstack.region.PortableIpRange;
import org.apache.cloudstack.usage.Usage;
import com.cloud.async.AsyncJob;
@@ -441,7 +443,12 @@ public interface ResponseGenerator {
Long getAffinityGroupId(String name, long entityOwnerId);
+ PortableIpRangeResponse createPortableIPRangeResponse(PortableIpRange range);
+
+ PortableIpResponse createPortableIPResponse(PortableIp portableIp);
+
InternalLoadBalancerElementResponse createInternalLbElementResponse(VirtualRouterProvider result);
-
+
IsolationMethodResponse createIsolationMethodResponse(IsolationType method);
+
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/api/command/admin/region/CreatePortableIpRangeCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/region/CreatePortableIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/region/CreatePortableIpRangeCmd.java
new file mode 100644
index 0000000..78e4c94
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/region/CreatePortableIpRangeCmd.java
@@ -0,0 +1,156 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.region;
+
+import javax.inject.Inject;
+
+import com.cloud.async.AsyncJob;
+import com.cloud.dc.Vlan;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceAllocationException;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCreateCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.PortableIpRangeResponse;
+import org.apache.cloudstack.api.response.RegionResponse;
+import org.apache.cloudstack.api.response.VlanIpRangeResponse;
+import org.apache.cloudstack.region.PortableIpRange;
+import org.apache.cloudstack.region.Region;
+import org.apache.cloudstack.region.RegionService;
+import org.apache.log4j.Logger;
+
+import com.cloud.user.Account;
+
+@APICommand(name = "createPortableIpRange", responseObject=PortableIpRangeResponse.class, description="adds a range of portable public IP's to a region", since="4.2.0")
+public class CreatePortableIpRangeCmd extends BaseAsyncCreateCmd {
+
+ public static final Logger s_logger = Logger.getLogger(CreatePortableIpRangeCmd.class.getName());
+
+ private static final String s_name = "createportableiprangeresponse";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name=ApiConstants.REGION_ID, type=CommandType.INTEGER, entityType = RegionResponse.class, required=true, description="Id of the Region")
+ private Integer regionId;
+
+ @Parameter(name=ApiConstants.START_IP, type=CommandType.STRING, required=true, description="the beginning IP address in the portable IP range")
+ private String startIp;
+
+ @Parameter(name=ApiConstants.END_IP, type=CommandType.STRING, required=true, description="the ending IP address in the portable IP range")
+ private String endIp;
+
+ @Parameter(name=ApiConstants.GATEWAY, type=CommandType.STRING, required=true, description="the gateway for the portable IP range")
+ private String gateway;
+
+ @Parameter(name=ApiConstants.NETMASK, type=CommandType.STRING, required=true, description="the netmask of the portable IP range")
+ private String netmask;
+
+ @Parameter(name=ApiConstants.VLAN, type=CommandType.STRING, description="VLAN id, if not specified defaulted to untagged")
+ private String vlan;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Integer getRegionId() {
+ return regionId;
+ }
+
+ public String getStartIp() {
+ return startIp;
+ }
+
+ public String getEndIp() {
+ return endIp;
+ }
+
+ public String getVlan() {
+ return vlan;
+ }
+
+ public String getGateway() {
+ return gateway;
+ }
+
+ public String getNetmask() {
+ return netmask;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ @Override
+ public void execute(){
+ PortableIpRange portableIpRange = _entityMgr.findById(PortableIpRange.class, getEntityId());
+ PortableIpRangeResponse response = null;
+ if (portableIpRange != null) {
+ response = _responseGenerator.createPortableIPRangeResponse(portableIpRange);
+ }
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+
+ @Override
+ public void create() throws ResourceAllocationException {
+ try {
+ PortableIpRange portableIpRange = _configService.createPortableIpRange(this);
+ if (portableIpRange != null) {
+ this.setEntityId(portableIpRange.getId());
+ this.setEntityUuid(portableIpRange.getUuid());
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create portable public IP range");
+ }
+ } catch (ConcurrentOperationException ex) {
+ s_logger.warn("Exception: ", ex);
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
+ }
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_PORTABLE_IP_RANGE_CREATE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "creating a portable public ip range in region: " + getRegionId();
+ }
+
+ @Override
+ public AsyncJob.Type getInstanceType() {
+ return AsyncJob.Type.PortableIpAddress;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/api/command/admin/region/DeletePortableIpRangeCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/region/DeletePortableIpRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/region/DeletePortableIpRangeCmd.java
new file mode 100644
index 0000000..856e8ef
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/region/DeletePortableIpRangeCmd.java
@@ -0,0 +1,93 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.region;
+
+import javax.inject.Inject;
+
+import com.cloud.async.AsyncJob;
+import com.cloud.event.EventTypes;
+import org.apache.cloudstack.api.*;
+import org.apache.cloudstack.api.response.PortableIpRangeResponse;
+import org.apache.cloudstack.api.response.RegionResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.region.Region;
+import org.apache.cloudstack.region.RegionService;
+import org.apache.log4j.Logger;
+
+import com.cloud.user.Account;
+
+@APICommand(name = "deletePortableIpRange", description="deletes a range of portable public IP's associated with a region", responseObject=SuccessResponse.class)
+public class DeletePortableIpRangeCmd extends BaseAsyncCmd {
+ public static final Logger s_logger = Logger.getLogger(DeletePortableIpRangeCmd.class.getName());
+
+ private static final String s_name = "deleteportablepublicipresponse";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+ @Parameter(name=ApiConstants.ID, type=CommandType.UUID, required=true, entityType = PortableIpRangeResponse.class, description="Id of the portable ip range")
+ private Long id;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getId() {
+ return id;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ @Override
+ public void execute(){
+ boolean result = _configService.deletePortableIpRange(this);
+ if (result) {
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ this.setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete portable ip range");
+ }
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_PORTABLE_IP_RANGE_DELETE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "deleting a portable public ip range";
+ }
+
+ @Override
+ public AsyncJob.Type getInstanceType() {
+ return AsyncJob.Type.PortableIpAddress;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/api/command/admin/region/ListPortableIpRangesCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/region/ListPortableIpRangesCmd.java b/api/src/org/apache/cloudstack/api/command/admin/region/ListPortableIpRangesCmd.java
new file mode 100644
index 0000000..75bcce0
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/region/ListPortableIpRangesCmd.java
@@ -0,0 +1,109 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.region;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.*;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.PortableIpRangeResponse;
+import org.apache.cloudstack.api.response.PortableIpResponse;
+import org.apache.cloudstack.api.response.RegionResponse;
+import org.apache.cloudstack.region.PortableIp;
+import org.apache.cloudstack.region.PortableIpRange;
+import org.apache.cloudstack.region.Region;
+import org.apache.cloudstack.region.RegionService;
+import org.apache.log4j.Logger;
+
+import com.cloud.user.Account;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@APICommand(name = "listPortableIpRanges", description="list portable IP ranges", responseObject=PortableIpRangeResponse.class)
+public class ListPortableIpRangesCmd extends BaseListCmd {
+
+ public static final Logger s_logger = Logger.getLogger(ListPortableIpRangesCmd.class.getName());
+
+ private static final String s_name = "listportableipresponse";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name=ApiConstants.REGION_ID, type=CommandType.INTEGER, required=false, description="Id of a Region")
+ private Integer regionId;
+
+ @Parameter(name=ApiConstants.ID, type=CommandType.UUID, required=false, entityType = PortableIpRangeResponse.class, description="Id of the portable ip range")
+ private Long id;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Integer getRegionIdId() {
+ return regionId;
+ }
+
+ public Long getPortableIpRangeId() {
+ return id;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ @Override
+ public void execute(){
+ ListResponse<PortableIpRangeResponse> response = new ListResponse<PortableIpRangeResponse>();
+ List<PortableIpRangeResponse> responses = new ArrayList<PortableIpRangeResponse>();
+ List<? extends PortableIpRange> portableIpRanges = new ArrayList<PortableIpRange>();
+
+ portableIpRanges = _configService.listPortableIpRanges(this);
+ if (portableIpRanges != null && !portableIpRanges.isEmpty()) {
+ for (PortableIpRange range : portableIpRanges) {
+ PortableIpRangeResponse rangeResponse = _responseGenerator.createPortableIPRangeResponse(range);
+
+ List<? extends PortableIp> portableIps = _configService.listPortableIps(range.getId());
+ if (portableIps != null && !portableIps.isEmpty()) {
+ List<PortableIpResponse> portableIpResponses = new ArrayList<PortableIpResponse>();
+ for (PortableIp portableIP: portableIps) {
+ PortableIpResponse portableIpresponse = _responseGenerator.createPortableIPResponse(portableIP);
+ portableIpResponses.add(portableIpresponse);
+ }
+ rangeResponse.setPortableIpResponses(portableIpResponses);
+ }
+
+ rangeResponse.setObjectName("portableiprange");
+ responses.add(rangeResponse);
+ }
+ }
+ response.setResponses(responses, portableIpRanges.size());
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java b/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java
index 28fbae4..f37e820 100644
--- a/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java
@@ -66,6 +66,14 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd {
"be associated with")
private Long vpcId;
+ @Parameter(name=ApiConstants.IS_PORTABLE, type = BaseCmd.CommandType.BOOLEAN, description = "should be set to true " +
+ "if public IP is required to be transferable across zones, if not specified defaults to false")
+ private Boolean isPortable;
+
+ @Parameter(name=ApiConstants.REGION_ID, type=CommandType.INTEGER, entityType = RegionResponse.class,
+ required=false, description="region ID from where portable ip is to be associated.")
+ private Integer regionId;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -107,6 +115,18 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd {
return vpcId;
}
+ public boolean isPortable() {
+ if (isPortable == null) {
+ return false;
+ } else {
+ return isPortable;
+ }
+ }
+
+ public Integer getRegionId() {
+ return regionId;
+ }
+
public Long getNetworkId() {
if (vpcId != null) {
return null;
@@ -196,7 +216,13 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd {
@Override
public void create() throws ResourceAllocationException{
try {
- IpAddress ip = _networkService.allocateIP(_accountService.getAccount(getEntityOwnerId()), getZoneId(), getNetworkId());
+ IpAddress ip = null;
+
+ if (!isPortable()) {
+ ip = _networkService.allocateIP(_accountService.getAccount(getEntityOwnerId()), getZoneId(), getNetworkId());
+ } else {
+ ip = _networkService.allocatePortableIP(_accountService.getAccount(getEntityOwnerId()), 1, getZoneId(), getNetworkId(), getVpcId());
+ }
if (ip != null) {
this.setEntityId(ip.getId());
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java b/api/src/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java
index 8271119..8f78fe3 100644
--- a/api/src/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java
@@ -74,7 +74,12 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
@Override
public void execute() throws InsufficientAddressCapacityException{
UserContext.current().setEventDetails("Ip Id: " + getIpAddressId());
- boolean result = _networkService.releaseIpAddress(getIpAddressId());
+ boolean result = false;
+ if (!isPortable(id)) {
+ _networkService.releaseIpAddress(getIpAddressId());
+ } else {
+ _networkService.releaseIpAddress(getIpAddressId());
+ }
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
@@ -139,4 +144,9 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
public Long getInstanceId() {
return getIpAddressId();
}
+
+ private boolean isPortable(long id) {
+ IpAddress ip = getIpAddress(id);
+ return ip.isPortable();
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java b/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java
index 902dbae..2e2e150 100644
--- a/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/nat/EnableStaticNatCmd.java
@@ -91,6 +91,12 @@ public class EnableStaticNatCmd extends BaseCmd{
} else {
ntwkId = networkId;
}
+
+ // in case of portable public IP, network ID passed takes precedence
+ if (ip.isPortable() && networkId != null ) {
+ ntwkId = networkId;
+ }
+
if (ntwkId == null) {
throw new InvalidParameterValueException("Unable to enable static nat for the ipAddress id=" + ipAddressId +
" as ip is not associated with any network and no networkId is passed in");
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java b/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java
index cede84f..e3d5cc6 100644
--- a/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/IPAddressResponse.java
@@ -115,6 +115,9 @@ public class IPAddressResponse extends BaseResponse implements ControlledEntityR
@SerializedName(ApiConstants.TAGS) @Param(description="the list of resource tags associated with ip address", responseObject = ResourceTagResponse.class)
private List<ResourceTagResponse> tags;
+ @SerializedName(ApiConstants.IS_PORTABLE) @Param(description = "is public IP portable across the zones")
+ private Boolean isPortable;
+
/*
@SerializedName(ApiConstants.JOB_ID) @Param(description="shows the current pending asynchronous job ID. This tag is not returned if no current pending jobs are acting on the volume")
private IdentityProxy jobId = new IdentityProxy("async_job");
@@ -247,4 +250,8 @@ public class IPAddressResponse extends BaseResponse implements ControlledEntityR
public void setAssociatedNetworkName(String associatedNetworkName) {
this.associatedNetworkName = associatedNetworkName;
}
+
+ public void setPortable(Boolean portable) {
+ this.isPortable = portable;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/api/response/PortableIpRangeResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/PortableIpRangeResponse.java b/api/src/org/apache/cloudstack/api/response/PortableIpRangeResponse.java
new file mode 100644
index 0000000..e7a15b8
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/response/PortableIpRangeResponse.java
@@ -0,0 +1,93 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.response;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+
+import com.cloud.network.IpAddress;
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.region.PortableIpRange;
+
+@EntityReference(value=PortableIpRange.class)
+public class PortableIpRangeResponse extends BaseResponse {
+
+ @SerializedName(ApiConstants.ID)
+ @Param(description = "portable IP range ID")
+ private String id;
+
+ @SerializedName(ApiConstants.REGION_ID)
+ @Param(description = "Region Id in which portable ip range is provisioned")
+ private Integer regionId;
+
+ @SerializedName(ApiConstants.GATEWAY) @Param(description="the gateway of the VLAN IP range")
+ private String gateway;
+
+ @SerializedName(ApiConstants.NETMASK) @Param(description="the netmask of the VLAN IP range")
+ private String netmask;
+
+ @SerializedName(ApiConstants.VLAN) @Param(description="the ID or VID of the VLAN.")
+ private String vlan;
+
+ @SerializedName(ApiConstants.START_IP) @Param(description="the start ip of the portable IP range")
+ private String startIp;
+
+ @SerializedName(ApiConstants.END_IP) @Param(description="the end ip of the portable IP range")
+ private String endIp;
+
+ @SerializedName(ApiConstants.PORTABLE_IP_ADDRESS)
+ @Param(description="List of portable IP and association with zone/network/vpc details that are part of GSLB rule", responseObject = PortableIpResponse.class)
+ private List<PortableIpResponse> portableIpResponses;
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setRegionId(int regionId) {
+ this.regionId = regionId;
+ }
+
+ public void setStartIp(String startIp) {
+ this.startIp = startIp;
+ }
+
+ public void setEndIp(String endIp) {
+ this.endIp = endIp;
+ }
+
+ public void setNetmask(String netmask) {
+ this.netmask = netmask;
+ }
+
+ public void setGateway(String gateway) {
+ this.gateway = gateway;
+ }
+
+ public void setVlan(String vlan) {
+ this.vlan = vlan;
+ }
+
+ public void setPortableIpResponses(List<PortableIpResponse> portableIpResponses) {
+ this.portableIpResponses = portableIpResponses;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/api/response/PortableIpResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/PortableIpResponse.java b/api/src/org/apache/cloudstack/api/response/PortableIpResponse.java
new file mode 100644
index 0000000..0ccbcc3
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/response/PortableIpResponse.java
@@ -0,0 +1,106 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.response;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+
+import com.cloud.network.IpAddress;
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.region.PortableIp;
+import org.apache.cloudstack.region.PortableIpRange;
+
+@EntityReference(value=PortableIp.class)
+public class PortableIpResponse extends BaseResponse {
+
+ @SerializedName(ApiConstants.REGION_ID)
+ @Param(description = "Region Id in which global load balancer is created")
+ private Integer regionId;
+
+ @SerializedName(ApiConstants.IP_ADDRESS) @Param(description="public IP address")
+ private String ipAddress;
+
+ @SerializedName(ApiConstants.ZONE_ID) @Param(description="the ID of the zone the public IP address belongs to")
+ private String zoneId;
+
+ @SerializedName(ApiConstants.NETWORK_ID) @Param(description="the ID of the Network where ip belongs to")
+ private String networkId;
+
+ @SerializedName(ApiConstants.VPC_ID) @Param(description="VPC the ip belongs to")
+ private String vpcId;
+
+ @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Param(description="the physical network this belongs to")
+ private String physicalNetworkId;
+
+ @SerializedName(ApiConstants.ACCOUNT_ID) @Param(description="the account ID the portable IP address is associated with")
+ private String accountId;
+
+ @SerializedName(ApiConstants.DOMAIN_ID) @Param(description="the domain ID the portable IP address is associated with")
+ private String domainId;
+
+ @SerializedName("allocated") @Param(description="date the portal IP address was acquired")
+ private Date allocated;
+
+ @SerializedName(ApiConstants.STATE) @Param(description="State of the ip address. Can be: Allocatin, Allocated and Releasing")
+ private String state;
+
+ public void setRegionId(Integer regionId) {
+ this.regionId = regionId;
+ }
+
+ public void setAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+ public void setAssociatedDataCenterId(String zoneId) {
+ this.zoneId = zoneId;
+ }
+
+ public void setAssociatedWithNetworkId(String networkId) {
+ this.networkId = networkId;
+ }
+
+ public void setAssociatedWithVpcId(String vpcId) {
+ this.vpcId = vpcId;
+ }
+
+ public void setPhysicalNetworkId(String physicalNetworkId) {
+ this.physicalNetworkId = physicalNetworkId;
+ }
+
+ public void setAllocatedToAccountId(String accountId) {
+ this.accountId = accountId;
+ }
+
+ public void setAllocatedInDomainId(String domainId) {
+ this.domainId = domainId;
+ }
+
+ public void setAllocatedTime(Date allocatedTimetime) {
+ this.allocated = allocatedTimetime;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/region/PortableIp.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/region/PortableIp.java b/api/src/org/apache/cloudstack/region/PortableIp.java
new file mode 100644
index 0000000..b95071e
--- /dev/null
+++ b/api/src/org/apache/cloudstack/region/PortableIp.java
@@ -0,0 +1,58 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.region;
+
+import java.util.Date;
+
+import com.cloud.utils.net.Ip;
+import org.apache.cloudstack.api.InternalIdentity;
+
+public interface PortableIp extends InternalIdentity {
+
+ enum State {
+ Allocating, // The IP Address is being propagated to other network elements and is not ready for use yet.
+ Allocated, // The IP address is in used.
+ Releasing, // The IP address is being released for other network elements and is not ready for allocation.
+ Free // The IP address is ready to be allocated.
+ }
+
+ Long getAllocatedToAccountId();
+
+ Long getAllocatedInDomainId();
+
+ Date getAllocatedTime();
+
+ State getState();
+
+ int getRegionId();
+
+ Long getAssociatedDataCenterId();
+
+ Long getAssociatedWithNetworkId();
+
+ Long getAssociatedWithVpcId();
+
+ Long getPhysicalNetworkId();
+
+ String getAddress();
+
+ String getVlan();
+
+ String getNetmask();
+
+ String getGateway();
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/api/src/org/apache/cloudstack/region/PortableIpRange.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/region/PortableIpRange.java b/api/src/org/apache/cloudstack/region/PortableIpRange.java
new file mode 100644
index 0000000..413a540
--- /dev/null
+++ b/api/src/org/apache/cloudstack/region/PortableIpRange.java
@@ -0,0 +1,38 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.region;
+
+import org.apache.cloudstack.acl.InfrastructureEntity;
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+public interface PortableIpRange extends InfrastructureEntity, InternalIdentity, Identity {
+
+ public final static String UNTAGGED = "untagged";
+
+ public String getVlanTag();
+
+ public String getGateway();
+
+ public String getNetmask();
+
+ public int getRegionId();
+
+ public String getIpRange();
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/client/tomcatconf/applicationContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in
index b500fde..edf83a9 100644
--- a/client/tomcatconf/applicationContext.xml.in
+++ b/client/tomcatconf/applicationContext.xml.in
@@ -271,6 +271,8 @@
<bean id="physicalNetworkTrafficTypeDaoImpl" class="com.cloud.network.dao.PhysicalNetworkTrafficTypeDaoImpl" />
<bean id="podVlanDaoImpl" class="com.cloud.dc.dao.PodVlanDaoImpl" />
<bean id="podVlanMapDaoImpl" class="com.cloud.dc.dao.PodVlanMapDaoImpl" />
+ <bean id="PortableIpDaoImpl" class="org.apache.cloudstack.region.PortableIpDaoImpl" />
+ <bean id="PortableIpRangeDaoImpl" class="org.apache.cloudstack.region.PortableIpRangeDaoImpl" />
<bean id="portForwardingRulesDaoImpl" class="com.cloud.network.rules.dao.PortForwardingRulesDaoImpl" />
<bean id="portProfileDaoImpl" class="com.cloud.network.dao.PortProfileDaoImpl" />
<bean id="primaryDataStoreDaoImpl" class="org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl" />
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index 68a7511..fd5479f 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -628,6 +628,11 @@ addCiscoAsa1000vResource=1
deleteCiscoAsa1000vResource=1
listCiscoAsa1000vResources=1
+#### portable public IP commands
+createPortableIpRange=1
+deletePortableIpRange=1
+listPortableIpRanges=1
+
#### Internal LB VM commands
stopInternalLoadBalancerVM=1
startInternalLoadBalancerVM=1
@@ -635,3 +640,4 @@ listInternalLoadBalancerVMs=1
### Network Isolation methods listing
listNetworkIsolationMethods=1
+
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/engine/schema/src/com/cloud/network/dao/IPAddressVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/network/dao/IPAddressVO.java b/engine/schema/src/com/cloud/network/dao/IPAddressVO.java
index ae27e95..5eb2500 100644
--- a/engine/schema/src/com/cloud/network/dao/IPAddressVO.java
+++ b/engine/schema/src/com/cloud/network/dao/IPAddressVO.java
@@ -111,6 +111,8 @@ public class IPAddressVO implements IpAddress {
@Column(name="dnat_vmip")
private String vmIp;
+ @Column(name="is_portable")
+ private boolean portable = false;
protected IPAddressVO() {
this.uuid = UUID.randomUUID().toString();
@@ -134,6 +136,19 @@ public class IPAddressVO implements IpAddress {
this.uuid = UUID.randomUUID().toString();
}
+ public IPAddressVO(Ip address, long dataCenterId, Long networkId, Long vpcId, long physicalNetworkId, long sourceNetworkId,
+ long vlanDbId, boolean portable) {
+ this.address = address;
+ this.dataCenterId = dataCenterId;
+ this.associatedWithNetworkId = networkId;
+ this.vpcId = vpcId;
+ this.physicalNetworkId = physicalNetworkId;
+ this.sourceNetworkId = sourceNetworkId;
+ this.vlanId = vlanDbId;
+ this.portable = portable;
+ this.uuid = UUID.randomUUID().toString();
+ }
+
public long getMacAddress() {
return macAddress;
}
@@ -283,6 +298,15 @@ public class IPAddressVO implements IpAddress {
this.system = isSystem;
}
+ @Override
+ public boolean isPortable() {
+ return portable;
+ }
+
+ public void setPortable(boolean portable) {
+ this.portable = portable;
+ }
+
@Override
public Long getVpcId() {
return vpcId;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/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 49e36dc..fc1c6a0 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -49,6 +49,8 @@ import org.apache.cloudstack.api.ApiConstants.VMDetails;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
+import org.apache.cloudstack.region.PortableIp;
+import org.apache.cloudstack.region.PortableIpRange;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.ApplicationLoadBalancerInstanceResponse;
import org.apache.cloudstack.api.response.ApplicationLoadBalancerResponse;
@@ -98,6 +100,8 @@ import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
import org.apache.cloudstack.api.response.PodResponse;
+import org.apache.cloudstack.api.response.PortableIpRangeResponse;
+import org.apache.cloudstack.api.response.PortableIpResponse;
import org.apache.cloudstack.api.response.PrivateGatewayResponse;
import org.apache.cloudstack.api.response.ProjectAccountResponse;
import org.apache.cloudstack.api.response.ProjectInvitationResponse;
@@ -722,6 +726,8 @@ public class ApiResponseHelper implements ResponseGenerator {
}
}
+ ipResponse.setPortable(ipAddr.isPortable());
+
//set tag information
List<? extends ResourceTag> tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.PublicIpAddress, ipAddr.getId());
List<ResourceTagResponse> tagResponses = new ArrayList<ResourceTagResponse>();
@@ -3824,6 +3830,69 @@ public class ApiResponseHelper implements ResponseGenerator {
}
}
+ @Override
+ public PortableIpRangeResponse createPortableIPRangeResponse(PortableIpRange ipRange) {
+ PortableIpRangeResponse response = new PortableIpRangeResponse();
+ response.setId(ipRange.getUuid());
+ String ipRangeStr = ipRange.getIpRange();
+ if (ipRangeStr != null) {
+ String[] range = ipRangeStr.split("-");
+ response.setStartIp(range[0]);
+ response.setEndIp(range[1]);
+ }
+ response.setVlan(ipRange.getVlanTag());
+ response.setGateway(ipRange.getGateway());
+ response.setNetmask(ipRange.getNetmask());
+ response.setRegionId(ipRange.getRegionId());
+ return response;
+ }
+
+ @Override
+ public PortableIpResponse createPortableIPResponse(PortableIp portableIp) {
+ PortableIpResponse response = new PortableIpResponse();
+ response.setAddress(portableIp.getAddress());
+ Long accountId = portableIp.getAllocatedInDomainId();
+ if (accountId != null) {
+ Account account = ApiDBUtils.findAccountById(accountId);
+ response.setAllocatedToAccountId(account.getAccountName());
+ Domain domain = ApiDBUtils.findDomainById(account.getDomainId());
+ response.setAllocatedInDomainId(domain.getUuid());
+ }
+
+ response.setAllocatedTime(portableIp.getAllocatedTime());
+
+ if (portableIp.getAssociatedDataCenterId() != null) {
+ DataCenter zone = ApiDBUtils.findZoneById(portableIp.getAssociatedDataCenterId());
+ if (zone != null) {
+ response.setAssociatedDataCenterId(zone.getUuid());
+ }
+ }
+
+ if (portableIp.getPhysicalNetworkId() != null) {
+ PhysicalNetwork pnw = ApiDBUtils.findPhysicalNetworkById(portableIp.getPhysicalNetworkId());
+ if (pnw != null) {
+ response.setPhysicalNetworkId(pnw.getUuid());
+ }
+ }
+
+ if (portableIp.getAssociatedWithNetworkId() != null) {
+ Network ntwk = ApiDBUtils.findNetworkById(portableIp.getAssociatedWithNetworkId());
+ if (ntwk != null) {
+ response.setAssociatedWithNetworkId(ntwk.getUuid());
+ }
+ }
+
+ if (portableIp.getAssociatedWithVpcId() != null) {
+ Vpc vpc = ApiDBUtils.findVpcById(portableIp.getAssociatedWithVpcId());
+ if (vpc != null) {
+ response.setAssociatedWithVpcId(vpc.getUuid());
+ }
+ }
+
+ response.setState(portableIp.getState().name());
+
+ return response;
+ }
@Override
public InternalLoadBalancerElementResponse createInternalLbElementResponse(VirtualRouterProvider result) {
@@ -3842,7 +3911,6 @@ public class ApiResponseHelper implements ResponseGenerator {
return response;
}
-
@Override
public IsolationMethodResponse createIsolationMethodResponse(IsolationType method) {
IsolationMethodResponse response = new IsolationMethodResponse();
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index 52d6176..47c5482 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -43,6 +43,7 @@ import com.cloud.dc.*;
import com.cloud.dc.dao.*;
import com.cloud.user.*;
import com.cloud.event.UsageEventUtils;
+import com.cloud.utils.db.*;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.api.ApiConstants.LDAPParams;
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
@@ -59,6 +60,9 @@ import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd;
import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd;
import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd;
import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd;
+import org.apache.cloudstack.api.command.admin.region.CreatePortableIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.region.DeletePortableIpRangeCmd;
+import org.apache.cloudstack.api.command.admin.region.ListPortableIpRangesCmd;
import org.apache.cloudstack.api.command.admin.vlan.CreateVlanIpRangeCmd;
import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd;
import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd;
@@ -67,6 +71,8 @@ import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd;
import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd;
import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd;
import org.apache.cloudstack.api.command.user.network.ListNetworkOfferingsCmd;
+import org.apache.cloudstack.region.*;
+import org.apache.cloudstack.region.dao.RegionDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
@@ -186,10 +192,6 @@ import com.cloud.utils.NumbersUtil;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.crypt.DBEncryptionUtil;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.db.Filter;
-import com.cloud.utils.db.SearchCriteria;
-import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.NicIpAlias;
@@ -332,6 +334,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
@Inject
VpcManager _vpcMgr;
@Inject
+ PortableIpRangeDao _portableIpRangeDao;
+ @Inject
+ RegionDao _regionDao;
+ @Inject
+ PortableIpDao _portableIpDao;
+ @Inject
ConfigurationServer _configServer;
@Inject
DcDetailsDao _dcDetailsDao;
@@ -4718,4 +4726,153 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
return null;
}
+
+ @Override
+ @DB
+ @ActionEvent(eventType = EventTypes.EVENT_PORTABLE_IP_RANGE_CREATE, eventDescription = "creating portable ip range", async = false)
+ public PortableIpRange createPortableIpRange(CreatePortableIpRangeCmd cmd) throws ConcurrentOperationException {
+ Integer regionId = cmd.getRegionId();
+ String startIP = cmd.getStartIp();
+ String endIP = cmd.getEndIp();
+ String gateway = cmd.getGateway();
+ String netmask = cmd.getNetmask();
+ Long userId = UserContext.current().getCallerUserId();
+ String vlanId = cmd.getVlan();
+
+ Region region = _regionDao.findById(regionId);
+ if (region == null) {
+ throw new InvalidParameterValueException("Invalid region ID: " + regionId);
+ }
+
+ if (!NetUtils.isValidIp(startIP) || !NetUtils.isValidIp(endIP) || !NetUtils.validIpRange(startIP, endIP)) {
+ throw new InvalidParameterValueException("Invalid portable ip range: " + startIP + "-" + endIP);
+ }
+
+ if (!NetUtils.sameSubnet(startIP, gateway, netmask)) {
+ throw new InvalidParameterValueException("Please ensure that your start IP is in the same subnet as " +
+ "your portable IP range's gateway and as per the IP range's netmask.");
+ }
+
+ if (!NetUtils.sameSubnet(endIP, gateway, netmask)) {
+ throw new InvalidParameterValueException("Please ensure that your end IP is in the same subnet as " +
+ "your portable IP range's gateway and as per the IP range's netmask.");
+ }
+
+ if (checkOverlapPortableIpRange(regionId, startIP, endIP)) {
+ throw new InvalidParameterValueException("Ip range: " + startIP + "-" + endIP + " overlaps with a portable" +
+ " IP range already configured in the region " + regionId);
+ }
+
+ if (vlanId == null) {
+ vlanId = Vlan.UNTAGGED;
+ } else {
+ if (!NetUtils.isValidVlan(vlanId)) {
+ throw new InvalidParameterValueException("Invalid vlan id " + vlanId);
+ }
+ }
+ GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange");
+ portableIpLock.lock(5);
+ Transaction txn = Transaction.currentTxn();
+ txn.start();
+
+ PortableIpRangeVO portableIpRange = new PortableIpRangeVO(regionId, vlanId, gateway, netmask, startIP, endIP);
+ portableIpRange = _portableIpRangeDao.persist(portableIpRange);
+
+ long startIpLong = NetUtils.ip2Long(startIP);
+ long endIpLong = NetUtils.ip2Long(endIP);
+ while(startIpLong <= endIpLong) {
+ PortableIpVO portableIP = new PortableIpVO(regionId, portableIpRange.getId(), vlanId,
+ gateway, netmask,NetUtils.long2Ip(startIpLong));
+ _portableIpDao.persist(portableIP);
+ startIpLong++;
+ }
+
+ txn.commit();
+ portableIpLock.unlock();
+ return portableIpRange;
+ }
+
+ @Override
+ @DB
+ @ActionEvent(eventType = EventTypes.EVENT_PORTABLE_IP_RANGE_DELETE, eventDescription = "deleting portable ip range", async = false)
+ public boolean deletePortableIpRange(DeletePortableIpRangeCmd cmd) {
+ long rangeId = cmd.getId();
+ PortableIpRangeVO portableIpRange = _portableIpRangeDao.findById(rangeId);
+ if (portableIpRange == null) {
+ throw new InvalidParameterValueException("Please specify a valid portable IP range id.");
+ }
+
+ List<PortableIpVO> fullIpRange = _portableIpDao.listByRangeId(portableIpRange.getId());
+ List<PortableIpVO> freeIpRange = _portableIpDao.listByRangeIdAndState(portableIpRange.getId(), PortableIp.State.Free);
+
+ if (fullIpRange != null && freeIpRange != null) {
+ if (fullIpRange.size() == freeIpRange.size()) {
+ _portableIpRangeDao.expunge(portableIpRange.getId());
+ return true;
+ } else {
+ throw new InvalidParameterValueException("Can't delete portable IP range as there are IP's assigned.");
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public List<? extends PortableIpRange> listPortableIpRanges(ListPortableIpRangesCmd cmd) {
+ Integer regionId = cmd.getRegionIdId();
+ Long rangeId = cmd.getPortableIpRangeId();
+
+ List <PortableIpRangeVO> ranges = new ArrayList<PortableIpRangeVO>();
+ if (regionId != null) {
+ Region region = _regionDao.findById(regionId);
+ if (region == null) {
+ throw new InvalidParameterValueException("Invalid region ID: " + regionId);
+ }
+ return _portableIpRangeDao.listByRegionId(regionId);
+ }
+
+ if (rangeId != null) {
+ PortableIpRangeVO range = _portableIpRangeDao.findById(rangeId);
+ if (range == null) {
+ throw new InvalidParameterValueException("Invalid portable IP range ID: " + regionId);
+ }
+ ranges.add(range);
+ return ranges;
+ }
+
+ return _portableIpRangeDao.listAll();
+ }
+
+ @Override
+ public List<? extends PortableIp> listPortableIps(long id) {
+
+ PortableIpRangeVO portableIpRange = _portableIpRangeDao.findById(id);
+ if (portableIpRange == null) {
+ throw new InvalidParameterValueException("Please specify a valid portable IP range id.");
+ }
+
+ return _portableIpDao.listByRangeId(portableIpRange.getId());
+ }
+
+ private boolean checkOverlapPortableIpRange(int regionId, String newStartIpStr, String newEndIpStr) {
+ long newStartIp = NetUtils.ip2Long(newStartIpStr);
+ long newEndIp = NetUtils.ip2Long(newEndIpStr);
+
+ List<PortableIpRangeVO> existingPortableIPRanges = _portableIpRangeDao.listByRegionId(regionId);
+ for (PortableIpRangeVO portableIpRange : existingPortableIPRanges) {
+ String ipRangeStr = portableIpRange.getIpRange();
+ String[] range = ipRangeStr.split("-");
+ long startip = NetUtils.ip2Long(range[0]);
+ long endIp = NetUtils.ip2Long(range[1]);
+
+ if ((newStartIp >= startip && newStartIp <= endIp) || (newEndIp >= startip && newEndIp <= endIp)) {
+ return true;
+ }
+
+ if ((startip >= newStartIp && startip <= newEndIp) || (endIp >= newStartIp && endIp <= newEndIp)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/com/cloud/network/NetworkManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java
index 08198ee..1e4fb84 100755
--- a/server/src/com/cloud/network/NetworkManager.java
+++ b/server/src/com/cloud/network/NetworkManager.java
@@ -59,6 +59,7 @@ import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.VirtualMachineProfile;
+import org.apache.cloudstack.region.PortableIp;
/**
* NetworkManager manages the network for the different end users.
@@ -240,6 +241,16 @@ public interface NetworkManager {
IPAddressVO associateIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException,
InsufficientAddressCapacityException, ConcurrentOperationException;
+ IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException,
+ InsufficientAddressCapacityException, ConcurrentOperationException;
+
+ IPAddressVO disassociatePortableIPToGuestNetwork(long ipAddrId, long networkId) throws ResourceAllocationException, ResourceUnavailableException,
+ InsufficientAddressCapacityException, ConcurrentOperationException;
+
+ boolean isPortableIpTransferableFromNetwork(long ipAddrId, long networkId);
+
+ void transferPortableIP(long ipAddrId, long currentNetworkId, long newNetworkId) throws ResourceAllocationException, ResourceUnavailableException,
+ InsufficientAddressCapacityException, ConcurrentOperationException;;
/**
* @param network
@@ -325,6 +336,9 @@ public interface NetworkManager {
DataCenter zone) throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException;
+ IpAddress allocatePortableIp(Account ipOwner, Account caller, long dcId, Long networkId, Long vpcID)
+ throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException;
+
Map<String, String> finalizeServicesAndProvidersForNetwork(NetworkOffering offering,
Long physicalNetworkId);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d6452be8/server/src/com/cloud/network/NetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java
index 40fc3d3..b3df0da 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -105,6 +105,10 @@ import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.dao.*;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.region.PortableIp;
+import org.apache.cloudstack.region.PortableIpDao;
+import org.apache.cloudstack.region.PortableIpVO;
+import org.apache.cloudstack.region.Region;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@@ -251,6 +255,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
UserIpv6AddressDao _ipv6Dao;
@Inject
Ipv6AddressManager _ipv6Mgr;
+ @Inject
+ PortableIpDao _portableIpDao;
protected StateMachine2<Network.State, Network.Event, Network> _stateMachine;
private final HashMap<String, NetworkOfferingVO> _systemNetworks = new HashMap<String, NetworkOfferingVO>(5);
@@ -702,6 +708,62 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
return ip;
}
+ @Override
+ @DB
+ public IpAddress allocatePortableIp(Account ipOwner, Account caller, long dcId, Long networkId, Long vpcID)
+ throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException {
+
+ Transaction txn = Transaction.currentTxn();
+ GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange");
+ PortableIpVO allocatedPortableIp;
+ IPAddressVO ipaddr;
+
+ try {
+ portableIpLock.lock(5);
+
+ txn.start();
+ //TODO: get the region ID corresponding to running management server
+ List<PortableIpVO> portableIpVOs = _portableIpDao.listByRegionIdAndState(1, PortableIp.State.Free);
+ if (portableIpVOs == null || portableIpVOs.isEmpty()) {
+ InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException
+ ("Unable to find available portable IP addresses", Region.class, new Long(1));
+ throw ex;
+ }
+
+ // allocate first portable IP to the user
+ allocatedPortableIp = portableIpVOs.get(0);
+ allocatedPortableIp.setAllocatedTime(new Date());
+ allocatedPortableIp.setAllocatedToAccountId(ipOwner.getAccountId());
+ allocatedPortableIp.setAllocatedInDomainId(ipOwner.getDomainId());
+ allocatedPortableIp.setState(PortableIp.State.Allocated);
+ _portableIpDao.update(allocatedPortableIp.getId(), allocatedPortableIp);
+
+ // provision portable IP range VLAN
+ long physicalNetworkId = _networkModel.getDefaultPhysicalNetworkByZoneAndTrafficType(dcId, TrafficType.Public).getId();
+ Network network = _networkModel.getNetwork(physicalNetworkId);
+ String range = allocatedPortableIp.getAddress() + "-" + allocatedPortableIp.getAddress();
+ VlanVO vlan = new VlanVO(VlanType.VirtualNetwork, allocatedPortableIp.getVlan(), allocatedPortableIp.getGateway(),
+ allocatedPortableIp.getNetmask(), dcId, range, network.getId(), network.getId(), null, null, null);
+ vlan = _vlanDao.persist(vlan);
+
+ // provision the portable IP in to user_ip_address table
+ ipaddr = new IPAddressVO(new Ip(allocatedPortableIp.getAddress()), dcId, networkId, vpcID, network.getId(),
+ network.getId(), vlan.getId(), true);
+ ipaddr.setState(State.Allocated);
+ ipaddr.setAllocatedTime(new Date());
+ ipaddr.setAllocatedInDomainId(ipOwner.getDomainId());
+ ipaddr.setAllocatedToAccountId(ipOwner.getId());
+ ipaddr= _ipAddressDao.persist(ipaddr);
+
+ txn.commit();
+
+ } finally {
+ portableIpLock.unlock();
+ }
+
+ return ipaddr;
+ }
+
protected IPAddressVO getExistingSourceNatInNetwork(long ownerId, Long networkId) {
List<? extends IpAddress> addrs = _networkModel.listPublicIpsAssignedToGuestNtwk(ownerId, networkId, true);
@@ -741,12 +803,14 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
}
DataCenter zone = _configMgr.getZone(network.getDataCenterId());
- if (network.getGuestType() == Network.GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced) {
- if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) {
- _accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.UseNetwork, false, network);
- } else {
- throw new InvalidParameterValueException("IP can be associated with guest network of 'shared' type only if " +
- "network services Source Nat, Static Nat, Port Forwarding, Load balancing, firewall are enabled in the network");
+ if (zone.getNetworkType() == NetworkType.Advanced) {
+ if (network.getGuestType() == Network.GuestType.Shared) {
+ if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) {
+ _accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.UseNetwork, false, network);
+ } else {
+ throw new InvalidParameterValueException("IP can be associated with guest network of 'shared' type only if " +
+ "network services Source Nat, Static Nat, Port Forwarding, Load balancing, firewall are enabled in the network");
+ }
}
} else {
_accountMgr.checkAccess(caller, null, true, ipToAssoc);
@@ -844,6 +908,162 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
}
}
+ @Override
+ public IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException,
+ InsufficientAddressCapacityException, ConcurrentOperationException {
+ return associateIPToGuestNetwork(ipAddrId, networkId, releaseOnFailure);
+ }
+
+ @DB
+ @Override
+ public IPAddressVO disassociatePortableIPToGuestNetwork(long ipId, long networkId)
+ throws ResourceAllocationException, ResourceUnavailableException,
+ InsufficientAddressCapacityException, ConcurrentOperationException {
+
+ Account caller = UserContext.current().getCaller();
+ Account owner = null;
+
+ Network network = _networksDao.findById(networkId);
+ if (network == null) {
+ throw new InvalidParameterValueException("Invalid network id is given");
+ }
+
+ IPAddressVO ipToAssoc = _ipAddressDao.findById(ipId);
+ if (ipToAssoc != null) {
+
+ if (ipToAssoc.getAssociatedWithNetworkId() == null) {
+ throw new InvalidParameterValueException("IP " + ipToAssoc + " is not associated with any network");
+ }
+
+ if (ipToAssoc.getAssociatedWithNetworkId() != network.getId()) {
+ throw new InvalidParameterValueException("IP " + ipToAssoc + " is not associated with network id" + networkId);
+ }
+
+ DataCenter zone = _configMgr.getZone(network.getDataCenterId());
+ if (zone.getNetworkType() == NetworkType.Advanced) {
+ if (network.getGuestType() == Network.GuestType.Shared) {
+ assert (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()));
+ _accountMgr.checkAccess(UserContext.current().getCaller(), AccessType.UseNetwork, false, network);
+ }
+ } else {
+ _accountMgr.checkAccess(caller, null, true, ipToAssoc);
+ }
+ owner = _accountMgr.getAccount(ipToAssoc.getAllocatedToAccountId());
+ } else {
+ s_logger.debug("Unable to find ip address by id: " + ipId);
+ return null;
+ }
+
+ DataCenter zone = _configMgr.getZone(network.getDataCenterId());
+
+ // Check that network belongs to IP owner - skip this check
+ // - if zone is basic zone as there is just one guest network,
+ // - if shared network in Advanced zone
+ // - and it belongs to the system
+ if (network.getAccountId() != owner.getId()) {
+ if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) {
+ throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP");
+ }
+ }
+
+ // Check if IP has any services (rules) associated in the network
+ List<PublicIpAddress> ipList = new ArrayList<PublicIpAddress>();
+ PublicIp publicIp = PublicIp.createFromAddrAndVlan(ipToAssoc, _vlanDao.findById(ipToAssoc.getVlanId()));
+ ipList.add(publicIp);
+ Map<PublicIpAddress, Set<Service>> ipToServices = _networkModel.getIpToServices(ipList, false, true);
+ if (ipToServices != null & !ipToServices.isEmpty()) {
+ Set<Service> services = ipToServices.get(publicIp);
+ if (services != null && !services.isEmpty()) {
+ throw new InvalidParameterValueException("IP " + ipToAssoc + " has services and rules associated in the network " + networkId);
+ }
+ }
+
+ IPAddressVO ip = _ipAddressDao.findById(ipId);
+ ip.setAssociatedWithNetworkId(null);
+ _ipAddressDao.update(ipId, ip);
+
+ try {
+ boolean success = applyIpAssociations(network, false);
+ if (success) {
+ s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " to network " + network);
+ } else {
+ s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network);
+ }
+ return ip;
+ } finally {
+
+ }
+ }
+
+ @Override
+ public boolean isPortableIpTransferableFromNetwork(long ipAddrId, long networkId) {
+ Network network = _networksDao.findById(networkId);
+ if (network == null) {
+ throw new InvalidParameterValueException("Invalid network id is given");
+ }
+
+ IPAddressVO ip = _ipAddressDao.findById(ipAddrId);
+ if (ip == null) {
+ throw new InvalidParameterValueException("Invalid network id is given");
+ }
+
+ // Check if IP has any services (rules) associated in the network
+ List<PublicIpAddress> ipList = new ArrayList<PublicIpAddress>();
+ PublicIp publicIp = PublicIp.createFromAddrAndVlan(ip, _vlanDao.findById(ip.getVlanId()));
+ ipList.add(publicIp);
+ Map<PublicIpAddress, Set<Service>> ipToServices = _networkModel.getIpToServices(ipList, false, true);
+ if (ipToServices != null & !ipToServices.isEmpty()) {
+ Set<Service> ipServices = ipToServices.get(publicIp);
+ if (ipServices != null && !ipServices.isEmpty()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @DB
+ @Override
+ public void transferPortableIP(long ipAddrId, long currentNetworkId, long newNetworkId) throws ResourceAllocationException, ResourceUnavailableException,
+ InsufficientAddressCapacityException, ConcurrentOperationException {
+
+ Network srcNetwork = _networksDao.findById(currentNetworkId);
+ if (srcNetwork == null) {
+ throw new InvalidParameterValueException("Invalid source network id " + currentNetworkId +" is given");
+ }
+
+ Network dstNetwork = _networksDao.findById(newNetworkId);
+ if (dstNetwork == null) {
+ throw new InvalidParameterValueException("Invalid source network id " + newNetworkId +" is given");
+ }
+
+ IPAddressVO ip = _ipAddressDao.findById(ipAddrId);
+ if (ip == null) {
+ throw new InvalidParameterValueException("Invalid portable ip address id is given");
+ }
+
+ Transaction txn = Transaction.currentTxn();
+ txn.start();
+
+ assert(isPortableIpTransferableFromNetwork(ipAddrId, currentNetworkId));
+
+ if (srcNetwork.getVpcId() != null) {
+ _vpcMgr.unassignIPFromVpcNetwork(ipAddrId, currentNetworkId);
+ } else {
+ disassociatePortableIPToGuestNetwork(ipAddrId, currentNetworkId);
+ }
+
+ associatePortableIPToGuestNetwork(ipAddrId, newNetworkId, false);
+
+ if (dstNetwork.getVpcId() != null) {
+ ip.setVpcId(dstNetwork.getVpcId());
+ } else {
+ ip.setVpcId(null);
+ }
+
+ _ipAddressDao.update(ipAddrId, ip);
+ txn.commit();
+ }
@Override
@DB
@@ -884,12 +1104,42 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
}
if (success) {
+ if (ip.isPortable()) {
+ releasePortableIpAddress(addrId);
+ }
s_logger.debug("Released a public ip id=" + addrId);
}
return success;
}
+ @DB
+ private void releasePortableIpAddress(long addrId) {
+ Transaction txn = Transaction.currentTxn();
+ GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange");
+
+ txn.start();
+ try {
+ portableIpLock.lock(5);
+ IPAddressVO ip = _ipAddressDao.findById(addrId);
+
+ // unassign portable IP
+ PortableIpVO portableIp = _portableIpDao.findByIpAddress(ip.getAddress().addr());
+ _portableIpDao.unassignIpAddress(portableIp.getId());
+
+ // removed the provisioned vlan
+ VlanVO vlan = _vlanDao.findById(ip.getVlanId());
+ _vlanDao.expunge(vlan.getId());
+
+ // remove the provisioned public ip address
+ _ipAddressDao.expunge(ip.getId());
+
+ txn.commit();
+ } finally {
+ portableIpLock.releaseRef();
+ }
+ }
+
@Override
@DB
public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {