From e7b2fb22557cb4ef0ce9c8dde3ed1b9c857038bf Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Sat, 11 May 2013 14:36:01 +0530 Subject: [PATCH] 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 --- api/src/com/cloud/async/AsyncJob.java | 1 + .../configuration/ConfigurationService.java | 10 + api/src/com/cloud/event/EventTypes.java | 3 + .../cloudstack/api/ResponseGenerator.java | 3 + .../region/CreatePortableIpRangeCmd.java | 156 ++++++++++++ .../region/DeletePortableIpRangeCmd.java | 93 ++++++++ .../admin/region/ListPortableIpRangesCmd.java | 96 ++++++++ .../api/response/PortableIpRangeResponse.java | 86 +++++++ .../api/response/PortableIpResponse.java | 106 +++++++++ .../apache/cloudstack/region/PortableIp.java | 58 +++++ .../cloudstack/region/PortableIpRange.java | 38 +++ client/tomcatconf/applicationContext.xml.in | 2 + client/tomcatconf/commands.properties.in | 4 + .../src/com/cloud/api/ApiResponseHelper.java | 18 ++ .../ConfigurationManagerImpl.java | 147 ++++++++++++ .../cloud/server/ManagementServerImpl.java | 11 +- .../cloudstack/region/PortableIpDao.java | 34 +++ .../cloudstack/region/PortableIpDaoImpl.java | 91 +++++++ .../cloudstack/region/PortableIpRangeDao.java | 30 +++ .../region/PortableIpRangeDaoImpl.java | 65 +++++ .../cloudstack/region/PortableIpRangeVO.java | 119 ++++++++++ .../cloudstack/region/PortableIpVO.java | 222 ++++++++++++++++++ .../vpc/MockConfigurationManagerImpl.java | 22 +- .../AffinityApiTestConfiguration.java | 6 +- .../ChildTestConfiguration.java | 8 +- setup/db/db/schema-410to420.sql | 34 +++ utils/src/com/cloud/utils/net/NetUtils.java | 12 + 27 files changed, 1464 insertions(+), 11 deletions(-) create mode 100644 api/src/org/apache/cloudstack/api/command/admin/region/CreatePortableIpRangeCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/region/DeletePortableIpRangeCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/admin/region/ListPortableIpRangesCmd.java create mode 100644 api/src/org/apache/cloudstack/api/response/PortableIpRangeResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/PortableIpResponse.java create mode 100644 api/src/org/apache/cloudstack/region/PortableIp.java create mode 100644 api/src/org/apache/cloudstack/region/PortableIpRange.java create mode 100755 server/src/org/apache/cloudstack/region/PortableIpDao.java create mode 100755 server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java create mode 100755 server/src/org/apache/cloudstack/region/PortableIpRangeDao.java create mode 100755 server/src/org/apache/cloudstack/region/PortableIpRangeDaoImpl.java create mode 100644 server/src/org/apache/cloudstack/region/PortableIpRangeVO.java create mode 100644 server/src/org/apache/cloudstack/region/PortableIpVO.java diff --git a/api/src/com/cloud/async/AsyncJob.java b/api/src/com/cloud/async/AsyncJob.java index 866429b6547..830e901a283 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, diff --git a/api/src/com/cloud/configuration/ConfigurationService.java b/api/src/com/cloud/configuration/ConfigurationService.java index 6937d0b64de..83b9aa2e364 100644 --- a/api/src/com/cloud/configuration/ConfigurationService.java +++ b/api/src/com/cloud/configuration/ConfigurationService.java @@ -34,6 +34,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; @@ -55,6 +58,7 @@ 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.PortableIpRange; public interface ConfigurationService { @@ -277,4 +281,10 @@ public interface ConfigurationService { * @return */ boolean isOfferingForVpc(NetworkOffering offering); + + PortableIpRange createPortableIpRange(CreatePortableIpRangeCmd cmd) throws ConcurrentOperationException; + + boolean deletePortableIpRange(DeletePortableIpRangeCmd cmd); + + List listPortableIpRanges(ListPortableIpRangesCmd cmd); } diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 0ee7f402fd7..9407a35c186 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -390,6 +390,9 @@ public class EventTypes { public static final String EVENT_AFFINITY_GROUP_REMOVE = "AG.REMOVE"; public static final String EVENT_VM_AFFINITY_GROUP_UPDATE = "VM.AG.UPDATE"; + 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 diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index cbf8bb27b90..aec74fd7cd3 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -102,6 +102,7 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.region.PortableIpRange; import org.apache.cloudstack.region.Region; import org.apache.cloudstack.usage.Usage; @@ -396,4 +397,6 @@ public interface ResponseGenerator { AffinityGroupResponse createAffinityGroupResponse(AffinityGroup group); Long getAffinityGroupId(String name, long entityOwnerId); + + PortableIpRangeResponse createPortableIPRangeResponse(PortableIpRange range); } 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 00000000000..78e4c94ed4c --- /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; + } +} 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 00000000000..856e8efa210 --- /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; + } +} 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 00000000000..6de81d2848c --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/region/ListPortableIpRangesCmd.java @@ -0,0 +1,96 @@ +// 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.RegionResponse; +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 response = new ListResponse(); + List responses = new ArrayList(); + List portableIpRanges = new ArrayList(); + + portableIpRanges = _configService.listPortableIpRanges(this); + if (portableIpRanges != null && !portableIpRanges.isEmpty()) { + for (PortableIpRange range : portableIpRanges) { + PortableIpRangeResponse rangeResponse = _responseGenerator.createPortableIPRangeResponse(range); + rangeResponse.setObjectName("portableiprange"); + responses.add(rangeResponse); + } + } + response.setResponses(responses, portableIpRanges.size()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } +} 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 00000000000..e4a5884d1af --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/PortableIpRangeResponse.java @@ -0,0 +1,86 @@ +// 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; + + 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; + } + +} 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 00000000000..0ccbcc3e5f6 --- /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; + } +} 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 00000000000..b95071e2456 --- /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(); +} 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 00000000000..413a540f92a --- /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(); + +} diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 1f5ab20333a..46a3e8656f4 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -267,6 +267,8 @@ + + diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index b49e1fbf5ff..6427546aa5f 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -591,3 +591,7 @@ addCiscoAsa1000vResource=1 deleteCiscoAsa1000vResource=1 listCiscoAsa1000vResources=1 +#### portable public IP commands +createPortableIpRange=1 +deletePortableIpRange=1 +listPortableIpRanges=1 diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 6090ff06d7c..0377aad3d95 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -127,6 +127,7 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.region.PortableIpRange; import org.apache.cloudstack.region.Region; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.usage.Usage; @@ -3714,4 +3715,21 @@ public class ApiResponseHelper implements ResponseGenerator { return ag.getId(); } } + + @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; + } } diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index d5e405d5395..520a3ed1f2d 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -56,6 +56,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; @@ -64,6 +67,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.log4j.Logger; import org.springframework.stereotype.Component; @@ -245,6 +250,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati FirewallRulesDao _firewallDao; @Inject VpcManager _vpcMgr; + @Inject + PortableIpRangeDao _portableIpRangeDao; + @Inject + RegionDao _regionDao; + @Inject + PortableIpDao _portableIpDao; // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao? @Inject protected DataCenterLinkLocalIpAddressDao _LinkLocalIpAllocDao; @@ -4265,4 +4276,140 @@ 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); + } + } + 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(); + + 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 fullIpRange = _portableIpDao.listByRangeId(portableIpRange.getId()); + List 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 listPortableIpRanges(ListPortableIpRangesCmd cmd) { + Integer regionId = cmd.getRegionIdId(); + Long rangeId = cmd.getPortableIpRangeId(); + + List ranges = new ArrayList(); + 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(); + } + + private boolean checkOverlapPortableIpRange(int regionId, String newStartIpStr, String newEndIpStr) { + long newStartIp = NetUtils.ip2Long(newStartIpStr); + long newEndIp = NetUtils.ip2Long(newEndIpStr); + + List 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; + } } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 5db8329928a..9edeb1aad09 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -34,7 +34,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; -import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -56,6 +55,7 @@ import org.apache.cloudstack.api.command.admin.domain.*; import org.apache.cloudstack.api.command.admin.host.*; import org.apache.cloudstack.api.command.admin.network.*; import org.apache.cloudstack.api.command.admin.offering.*; +import org.apache.cloudstack.api.command.admin.region.*; import org.apache.cloudstack.api.command.admin.resource.*; import org.apache.cloudstack.api.command.admin.router.*; import org.apache.cloudstack.api.command.admin.storage.*; @@ -114,7 +114,6 @@ import com.cloud.dc.*; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.dao.*; import com.cloud.deploy.DataCenterDeployment; -import com.cloud.deploy.DeploymentPlanner; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; @@ -148,7 +147,6 @@ import com.cloud.projects.ProjectManager; import com.cloud.resource.ResourceManager; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.server.auth.UserAuthenticator; -import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.*; import com.cloud.storage.Storage.ImageFormat; @@ -203,9 +201,7 @@ import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd; import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd; import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd; -import org.apache.cloudstack.api.command.admin.region.AddRegionCmd; -import org.apache.cloudstack.api.command.admin.region.RemoveRegionCmd; -import org.apache.cloudstack.api.command.admin.region.UpdateRegionCmd; +import org.apache.cloudstack.api.command.admin.region.ListPortableIpRangesCmd; import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd; import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd; import org.apache.cloudstack.api.command.admin.template.PrepareTemplateCmd; @@ -2496,6 +2492,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(ListAffinityGroupsCmd.class); cmdList.add(UpdateVMAffinityGroupCmd.class); cmdList.add(ListAffinityGroupTypesCmd.class); + cmdList.add(CreatePortableIpRangeCmd.class); + cmdList.add(DeletePortableIpRangeCmd.class); + cmdList.add(ListPortableIpRangesCmd.class); return cmdList; } diff --git a/server/src/org/apache/cloudstack/region/PortableIpDao.java b/server/src/org/apache/cloudstack/region/PortableIpDao.java new file mode 100755 index 00000000000..3512075656a --- /dev/null +++ b/server/src/org/apache/cloudstack/region/PortableIpDao.java @@ -0,0 +1,34 @@ +// 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.List; + +import com.cloud.dc.Vlan; +import com.cloud.dc.Vlan.VlanType; +import com.cloud.dc.VlanVO; +import com.cloud.utils.db.GenericDao; + +public interface PortableIpDao extends GenericDao { + + List listByRegionId(int regionId); + + List listByRangeId(long rangeId); + + List listByRangeIdAndState(long rangeId, PortableIp.State state); + +} diff --git a/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java b/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java new file mode 100755 index 00000000000..8989e828573 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/PortableIpDaoImpl.java @@ -0,0 +1,91 @@ +// 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.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.springframework.stereotype.Component; + +import com.cloud.dc.AccountVlanMapVO; +import com.cloud.dc.PodVlanMapVO; +import com.cloud.dc.Vlan; +import com.cloud.dc.Vlan.VlanType; +import com.cloud.dc.VlanVO; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.utils.Pair; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; + +@Component +@Local(value={PortableIpDao.class}) +public class PortableIpDaoImpl extends GenericDaoBase implements PortableIpDao { + + private final SearchBuilder listByRegionIDSearch; + private final SearchBuilder listByRangeIDSearch; + private final SearchBuilder listByRangeIDAndStateSearch; + + public PortableIpDaoImpl() { + listByRegionIDSearch = createSearchBuilder(); + listByRegionIDSearch.and("regionId", listByRegionIDSearch.entity().getRegionId(), SearchCriteria.Op.EQ); + listByRegionIDSearch.done(); + + listByRangeIDSearch = createSearchBuilder(); + listByRangeIDSearch.and("rangeId", listByRangeIDSearch.entity().getRangeId(), SearchCriteria.Op.EQ); + listByRangeIDSearch.done(); + + listByRangeIDAndStateSearch = createSearchBuilder(); + listByRangeIDAndStateSearch.and("rangeId", listByRangeIDAndStateSearch.entity().getRangeId(), SearchCriteria.Op.EQ); + listByRangeIDAndStateSearch.and("state", listByRangeIDAndStateSearch.entity().getState(), SearchCriteria.Op.EQ); + listByRangeIDAndStateSearch.done(); + } + + @Override + public List listByRegionId(int regionIdId) { + SearchCriteria sc = listByRegionIDSearch.create(); + sc.setParameters("regionId", regionIdId); + return listBy(sc); + } + + @Override + public List listByRangeId(long rangeId) { + SearchCriteria sc = listByRangeIDSearch.create(); + sc.setParameters("rangeId", rangeId); + return listBy(sc); + } + + @Override + public List listByRangeIdAndState(long rangeId, PortableIp.State state) { + SearchCriteria sc = listByRangeIDAndStateSearch.create(); + sc.setParameters("rangeId", rangeId); + sc.setParameters("state", state); + return listBy(sc); + } +} diff --git a/server/src/org/apache/cloudstack/region/PortableIpRangeDao.java b/server/src/org/apache/cloudstack/region/PortableIpRangeDao.java new file mode 100755 index 00000000000..85da6c0a87e --- /dev/null +++ b/server/src/org/apache/cloudstack/region/PortableIpRangeDao.java @@ -0,0 +1,30 @@ +// 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.List; + +import com.cloud.dc.Vlan; +import com.cloud.dc.Vlan.VlanType; +import com.cloud.dc.VlanVO; +import com.cloud.utils.db.GenericDao; + +public interface PortableIpRangeDao extends GenericDao { + + List listByRegionId(int regionId); + +} diff --git a/server/src/org/apache/cloudstack/region/PortableIpRangeDaoImpl.java b/server/src/org/apache/cloudstack/region/PortableIpRangeDaoImpl.java new file mode 100755 index 00000000000..496c9e6da40 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/PortableIpRangeDaoImpl.java @@ -0,0 +1,65 @@ +// 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.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.springframework.stereotype.Component; + +import com.cloud.dc.AccountVlanMapVO; +import com.cloud.dc.PodVlanMapVO; +import com.cloud.dc.Vlan; +import com.cloud.dc.Vlan.VlanType; +import com.cloud.dc.VlanVO; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.utils.Pair; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; + +@Component +@Local(value={PortableIpRangeDao.class}) +public class PortableIpRangeDaoImpl extends GenericDaoBase implements PortableIpRangeDao { + + private final SearchBuilder listByRegionIDSearch; + + public PortableIpRangeDaoImpl() { + listByRegionIDSearch = createSearchBuilder(); + listByRegionIDSearch.and("regionId", listByRegionIDSearch.entity().getRegionId(), SearchCriteria.Op.EQ); + listByRegionIDSearch.done(); + } + + @Override + public List listByRegionId(int regionIdId) { + SearchCriteria sc = listByRegionIDSearch.create(); + sc.setParameters("regionId", regionIdId); + return listBy(sc); + } +} diff --git a/server/src/org/apache/cloudstack/region/PortableIpRangeVO.java b/server/src/org/apache/cloudstack/region/PortableIpRangeVO.java new file mode 100644 index 00000000000..933fcc3d1d7 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/PortableIpRangeVO.java @@ -0,0 +1,119 @@ +// 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.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +@Entity +@Table(name="portable_ip_range") +public class PortableIpRangeVO implements PortableIpRange { + + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + Long id; + + @Column(name="uuid") + String uuid; + + @Column(name="region_id") + int regionId; + + @Column(name="vlan_id") + String vlan; + + @Column(name="gateway") + String gateway; + + @Column(name="netmask") + String netmask; + + @Column(name="start_ip") + String startIp; + + @Column(name="end_ip") + String endIp; + + public PortableIpRangeVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public PortableIpRangeVO(int regionId, String vlan, String gateway, String netmask, String startIp, String endIp) { + this.uuid = UUID.randomUUID().toString(); + this.regionId =regionId; + this.vlan = vlan; + this.gateway = gateway; + this.netmask = netmask; + this.startIp = startIp; + this.endIp = endIp; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return this.uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public String getVlanTag() { + return vlan; + } + + public void setVlanTag(String vlan) { + this.vlan = vlan; + } + + @Override + public String getGateway() { + return gateway; + } + + @Override + public String getNetmask() { + return netmask; + } + + @Override + public int getRegionId() { + return regionId; + } + + @Override + public String getIpRange() { + return startIp + "-" + endIp; + } +} diff --git a/server/src/org/apache/cloudstack/region/PortableIpVO.java b/server/src/org/apache/cloudstack/region/PortableIpVO.java new file mode 100644 index 00000000000..61ea87053c7 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/PortableIpVO.java @@ -0,0 +1,222 @@ +// 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 java.util.UUID; + +import javax.persistence.*; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +@Entity +@Table(name="portable_ip_address") +public class PortableIpVO implements PortableIp { + + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + Long id; + + @Column(name="region_id") + int regionId; + + @Column(name="allocated") + @Temporal(value=TemporalType.TIMESTAMP) + private Date allocatedTime; + + @Column(name="account_id") + private Long allocatedToAccountId = null; + + @Column(name="domain_id") + private Long allocatedInDomainId = null; + + @Column(name="state") + private State state; + + @Column(name="vlan") + String vlan; + + @Column(name="gateway") + String gateway; + + @Column(name="netmask") + String netmask; + + @Column(name="portable_ip_address") + String address; + + @Column(name="portable_ip_range_id") + private long rangeId; + + @Column(name="physical_network_id") + private Long physicalNetworkId; + + @Column(name="data_center_id") + private long dataCenterId; + + @Column(name="network_id") + private Long networkId; + + @Column(name="vpc_id") + private Long vpcId; + + public PortableIpVO() { + + } + + public PortableIpVO(int regionId, Long rangeId, String vlan, String gateway, String netmask, String address) { + this.regionId =regionId; + this.vlan = vlan; + this.gateway = gateway; + this.netmask = netmask; + this.address = address; + state = State.Free; + this.rangeId = rangeId; + } + + @Override + public long getId() { + return id; + } + + @Override + public Long getAllocatedToAccountId() { + return allocatedToAccountId; + } + + public void setAllocatedToAccountId(Long accountId) { + this.allocatedToAccountId = accountId; + } + + @Override + public Long getAllocatedInDomainId() { + return allocatedInDomainId; + } + + public void setAllocatedInDomainId(Long domainId) { + this.allocatedInDomainId = domainId; + } + + @Override + public Date getAllocatedTime() { + return allocatedTime; + } + + public void setAllocatedTime(Date date) { + this.allocatedTime = date; + } + + @Override + public State getState() { + return state; + } + + public void setState(State state) { + this.state = state; + } + + @Override + public int getRegionId() { + return regionId; + } + + public void setRegionId(int regionId) { + this.regionId = regionId; + } + + @Override + public Long getAssociatedDataCenterId() { + return dataCenterId; + } + + public void setAssociatedDataCenterId(Long datacenterId) { + this.dataCenterId = datacenterId; + } + + @Override + public Long getAssociatedWithNetworkId() { + return networkId; + } + + public void setAssociatedWithNetworkId(Long networkId) { + this.networkId = networkId; + } + + @Override + public Long getAssociatedWithVpcId() { + return vpcId; + } + + public void setAssociatedWithVpcId(Long vpcId) { + this.vpcId = vpcId; + } + + @Override + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public void setPhysicalNetworkId(Long physicalNetworkId) { + this.physicalNetworkId = physicalNetworkId; + } + + @Override + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + @Override + public String getVlan() { + return vlan; + } + + public void setVlan(String vlan) { + this.vlan = vlan; + } + + @Override + public String getNetmask() { + return netmask; + } + + public void setNetmask(String netmask) { + this.netmask = netmask; + } + + @Override + public String getGateway() { + return gateway; + } + + public void setGateay(String gateway) { + this.gateway = gateway; + } + + Long getRangeId() { + return rangeId; + } + + public void setRangeId(Long rangeId) { + this.rangeId = rangeId; + } +} diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index 6cda294fbe7..81aec379d83 100755 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -25,7 +25,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import javax.naming.NamingException; -import com.cloud.configuration.ConfigurationVO; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd; import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd; @@ -40,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; @@ -48,6 +50,7 @@ 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.PortableIpRange; import org.springframework.stereotype.Component; import com.cloud.configuration.Configuration; @@ -75,13 +78,11 @@ import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offering.ServiceOffering; import com.cloud.offerings.NetworkOfferingVO; -import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingDaoImpl; import com.cloud.org.Grouping.AllocationState; import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.DiskOfferingVO; import com.cloud.user.Account; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.VirtualMachine.Type; @@ -386,6 +387,21 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu return false; } + @Override + public PortableIpRange createPortableIpRange(CreatePortableIpRangeCmd cmd) throws ConcurrentOperationException { + return null;// TODO Auto-generated method stub + } + + @Override + public boolean deletePortableIpRange(DeletePortableIpRangeCmd cmd) { + return false; + } + + @Override + public List listPortableIpRanges(ListPortableIpRangesCmd cmd) { + return null;// TODO Auto-generated method stub + } + /* (non-Javadoc) * @see com.cloud.utils.component.Manager#configure(java.lang.String, java.util.Map) */ diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java index fb294697cc6..e92c1cb0f4a 100644 --- a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java @@ -21,6 +21,9 @@ import java.io.IOException; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; +import org.apache.cloudstack.region.PortableIpDaoImpl; +import org.apache.cloudstack.region.PortableIpRangeDaoImpl; +import org.apache.cloudstack.region.dao.RegionDaoImpl; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; @@ -131,7 +134,8 @@ import com.cloud.vm.dao.VMInstanceDaoImpl; FirewallRulesCidrsDaoImpl.class, PhysicalNetworkDaoImpl.class, PhysicalNetworkTrafficTypeDaoImpl.class, PhysicalNetworkServiceProviderDaoImpl.class, LoadBalancerDaoImpl.class, NetworkServiceMapDaoImpl.class, PrimaryDataStoreDaoImpl.class, StoragePoolDetailsDaoImpl.class, AffinityGroupServiceImpl.class, - ComponentContext.class, AffinityGroupProcessor.class, UserVmVO.class, EventUtils.class, UserVmVO.class + ComponentContext.class, AffinityGroupProcessor.class, UserVmVO.class, EventUtils.class, UserVmVO.class, + PortableIpRangeDaoImpl.class, RegionDaoImpl.class, PortableIpDaoImpl.class }, includeFilters = { @Filter(value = AffinityApiTestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) public class AffinityApiTestConfiguration { diff --git a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java index f1163ef35ee..55ddcde5112 100644 --- a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java +++ b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java @@ -20,6 +20,8 @@ package org.apache.cloudstack.networkoffering; import java.io.IOException; import org.apache.cloudstack.acl.SecurityChecker; +import org.apache.cloudstack.region.PortableIpDaoImpl; +import org.apache.cloudstack.region.dao.RegionDaoImpl; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; @@ -109,6 +111,7 @@ import com.cloud.vm.dao.NicDaoImpl; import com.cloud.vm.dao.NicSecondaryIpDaoImpl; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDaoImpl; +import org.apache.cloudstack.region.PortableIpRangeDaoImpl; @Configuration @ComponentScan(basePackageClasses={ @@ -156,7 +159,10 @@ import com.cloud.vm.dao.VMInstanceDaoImpl; LoadBalancerDaoImpl.class, NetworkServiceMapDaoImpl.class, PrimaryDataStoreDaoImpl.class, - StoragePoolDetailsDaoImpl.class + StoragePoolDetailsDaoImpl.class, + PortableIpRangeDaoImpl.class, + RegionDaoImpl.class, + PortableIpDaoImpl.class }, includeFilters={@Filter(value=ChildTestConfiguration.Library.class, type=FilterType.CUSTOM)}, useDefaultFilters=false diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 78444fd5576..bda2c4c8c09 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -1110,3 +1110,37 @@ CREATE VIEW `cloud`.`account_view` AS and async_job.job_status = 0; alter table `cloud_usage`.`usage_network_offering` add column nic_id bigint(20) unsigned NOT NULL; + +CREATE TABLE `cloud`.`portable_ip_range` ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, + `uuid` varchar(40), + `region_id` int unsigned NOT NULL, + `vlan_id` varchar(255), + `gateway` varchar(255), + `netmask` varchar(255), + `start_ip` varchar(255), + `end_ip` varchar(255), + PRIMARY KEY (`id`), + CONSTRAINT `fk_portableip__region_id` FOREIGN KEY (`region_id`) REFERENCES `region`(`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`portable_ip_address` ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, + `account_id` bigint unsigned NULL, + `domain_id` bigint unsigned NULL, + `allocated` datetime NULL COMMENT 'Date portable ip was allocated', + `state` char(32) NOT NULL default 'Free' COMMENT 'state of the portable ip address', + `region_id` int unsigned NOT NULL, + `vlan` varchar(255), + `gateway` varchar(255), + `netmask` varchar(255), + `portable_ip_address` varchar(255), + `portable_ip_range_id` bigint unsigned NOT NULL, + `data_center_id` bigint unsigned NULL COMMENT 'zone to which portable IP is associated', + `physical_network_id` bigint unsigned NULL COMMENT 'physical network id in the zone to which portable IP is associated', + `network_id` bigint unsigned NULL COMMENT 'guest network to which portable ip address is associated with', + `vpc_id` bigint unsigned COMMENT 'vpc to which portable ip address is associated with', + PRIMARY KEY (`id`), + CONSTRAINT `fk_portable_ip_address__portable_ip_range_id` FOREIGN KEY (`portable_ip_range_id`) REFERENCES `portable_ip_range`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_portable_ip_address__region_id` FOREIGN KEY (`region_id`) REFERENCES `region`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index 5988dd5f337..77c593af84f 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -1290,4 +1290,16 @@ public class NetUtils { } return resultIp; } + + public static boolean isValidVlan(String vlan) { + try { + int vnet = Integer.parseInt(vlan); + if (vnet < 0 || vnet > 4096) { + return false; + } + return true; + } catch (NumberFormatException e) { + return false; + } + } }