diff --git a/INSTALL.md b/INSTALL.md index 61ebadfdc3d..00c724b11b4 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -52,8 +52,9 @@ server are available and not blocked by any local firewall. Following ports are used by Apache CloudStack and its entities: 8787: Apache CloudStack (Tomcat) debug socket - 9090, 8250: Apache CloudStack Management Server, User/Client API + 9090, 8250, 8080: Apache CloudStack Management Server, User/Client API 8096: User/Client to CloudStack Management Server (unauthenticated) + 7080: AWS API Server 3306: MySQL Server 3922, 8250, 80/443, 111/2049, 53: Secondary Storage VM 3922, 8250, 53: Console Proxy VM diff --git a/api/src/com/cloud/agent/api/routing/DhcpEntryCommand.java b/api/src/com/cloud/agent/api/routing/DhcpEntryCommand.java index 5c2cd582d4c..f0ce70e9a80 100644 --- a/api/src/com/cloud/agent/api/routing/DhcpEntryCommand.java +++ b/api/src/com/cloud/agent/api/routing/DhcpEntryCommand.java @@ -28,7 +28,9 @@ public class DhcpEntryCommand extends NetworkElementCommand { String defaultRouter; String staticRoutes; String defaultDns; - + String vmIp6Address; + String ip6Gateway; + String duid; protected DhcpEntryCommand() { @@ -39,14 +41,15 @@ public class DhcpEntryCommand extends NetworkElementCommand { return true; } - public DhcpEntryCommand(String vmMac, String vmIpAddress, String vmName) { + public DhcpEntryCommand(String vmMac, String vmIpAddress, String vmName, String vmIp6Address) { this.vmMac = vmMac; this.vmIpAddress = vmIpAddress; this.vmName = vmName; + this.vmIp6Address = vmIp6Address; } - public DhcpEntryCommand(String vmMac, String vmIpAddress, String vmName, String dns, String gateway) { - this(vmMac, vmIpAddress, vmName); + public DhcpEntryCommand(String vmMac, String vmIpAddress, String vmName, String vmIp6Address, String dns, String gateway, String ip6Gateway) { + this(vmMac, vmIpAddress, vmName, vmIp6Address); this.dns = dns; this.gateway = gateway; } @@ -102,4 +105,28 @@ public class DhcpEntryCommand extends NetworkElementCommand { public void setDefaultDns(String defaultDns) { this.defaultDns = defaultDns; } + + public String getIp6Gateway() { + return ip6Gateway; + } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public String getDuid() { + return duid; + } + + public void setDuid(String duid) { + this.duid = duid; + } + + public String getVmIp6Address() { + return vmIp6Address; + } + + public void setVmIp6Address(String ip6Address) { + this.vmIp6Address = ip6Address; + } } diff --git a/api/src/com/cloud/dc/Vlan.java b/api/src/com/cloud/dc/Vlan.java index 0f629ef3cbf..790195f9f3c 100644 --- a/api/src/com/cloud/dc/Vlan.java +++ b/api/src/com/cloud/dc/Vlan.java @@ -44,4 +44,9 @@ public interface Vlan extends InfrastructureEntity, InternalIdentity, Identity { public Long getPhysicalNetworkId(); + public String getIp6Gateway(); + + public String getIp6Cidr(); + + public String getIp6Range(); } diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index df7a3da3bef..27977f94f7b 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -256,6 +256,32 @@ public interface Network extends ControlledEntity, InternalIdentity, Identity { } } + public class IpAddresses { + private String ip4Address; + private String ip6Address; + + public IpAddresses(String ip4Address, String ip6Address) { + this.setIp4Address(ip4Address); + this.setIp6Address(ip6Address); + } + + public String getIp4Address() { + return ip4Address; + } + + public void setIp4Address(String ip4Address) { + this.ip4Address = ip4Address; + } + + public String getIp6Address() { + return ip6Address; + } + + public void setIp6Address(String ip6Address) { + this.ip6Address = ip6Address; + } + } + String getName(); Mode getMode(); @@ -268,6 +294,10 @@ public interface Network extends ControlledEntity, InternalIdentity, Identity { String getCidr(); + String getIp6Gateway(); + + String getIp6Cidr(); + long getDataCenterId(); long getNetworkOfferingId(); diff --git a/api/src/com/cloud/network/NetworkModel.java b/api/src/com/cloud/network/NetworkModel.java index 9baa0ec435c..7e17405f434 100644 --- a/api/src/com/cloud/network/NetworkModel.java +++ b/api/src/com/cloud/network/NetworkModel.java @@ -249,4 +249,5 @@ public interface NetworkModel { boolean isNetworkInlineMode(Network network); + Vlan getVlanForNetwork(long networkId); } \ No newline at end of file diff --git a/api/src/com/cloud/network/NetworkProfile.java b/api/src/com/cloud/network/NetworkProfile.java index 067ba15954b..37d46ac8395 100644 --- a/api/src/com/cloud/network/NetworkProfile.java +++ b/api/src/com/cloud/network/NetworkProfile.java @@ -38,6 +38,8 @@ public class NetworkProfile implements Network { private TrafficType trafficType; private String gateway; private String cidr; + private String ip6Gateway; + private String ip6Cidr; private long networkOfferingId; private long related; private String displayText; @@ -63,6 +65,8 @@ public class NetworkProfile implements Network { this.trafficType = network.getTrafficType(); this.gateway = network.getGateway(); this.cidr = network.getCidr(); + this.ip6Gateway = network.getIp6Gateway(); + this.ip6Cidr = network.getIp6Cidr(); this.networkOfferingId = network.getNetworkOfferingId(); this.related = network.getRelated(); this.displayText = network.getDisplayText(); @@ -229,4 +233,14 @@ public class NetworkProfile implements Network { public void setTrafficType(TrafficType type) { this.trafficType = type; } + + @Override + public String getIp6Gateway() { + return ip6Gateway; + } + + @Override + public String getIp6Cidr() { + return ip6Cidr; + } } diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java index b15661910b4..e3d21584ad8 100755 --- a/api/src/com/cloud/network/Networks.java +++ b/api/src/com/cloud/network/Networks.java @@ -48,7 +48,7 @@ public class Networks { public enum AddressFormat { Ip4, Ip6, - Mixed + DualStack } /** diff --git a/api/src/com/cloud/vm/Nic.java b/api/src/com/cloud/vm/Nic.java index 51f25f59b75..9d21130327a 100644 --- a/api/src/com/cloud/vm/Nic.java +++ b/api/src/com/cloud/vm/Nic.java @@ -145,4 +145,10 @@ public interface Nic extends Identity, InternalIdentity { VirtualMachine.Type getVmType(); AddressFormat getAddressFormat(); + + String getIp6Gateway(); + + String getIp6Cidr(); + + String getIp6Address(); } diff --git a/api/src/com/cloud/vm/NicProfile.java b/api/src/com/cloud/vm/NicProfile.java index bf11786d58d..e9e091cc2d7 100644 --- a/api/src/com/cloud/vm/NicProfile.java +++ b/api/src/com/cloud/vm/NicProfile.java @@ -38,6 +38,8 @@ public class NicProfile implements InternalIdentity { TrafficType trafficType; String ip4Address; String ip6Address; + String ip6Gateway; + String ip6Cidr; String macAddress; URI isolationUri; String netmask; @@ -51,7 +53,8 @@ public class NicProfile implements InternalIdentity { Integer networkRate; boolean isSecurityGroupEnabled; String name; - String requestedIp; + String requestedIpv4; + String requestedIpv6; public String getDns1() { return dns1; @@ -219,7 +222,7 @@ public class NicProfile implements InternalIdentity { this.trafficType = network.getTrafficType(); this.ip4Address = nic.getIp4Address(); this.format = nic.getAddressFormat(); - this.ip6Address = null; + this.ip6Address = nic.getIp6Address(); this.macAddress = nic.getMacAddress(); this.reservationId = nic.getReservationId(); this.strategy = nic.getReservationStrategy(); @@ -231,6 +234,8 @@ public class NicProfile implements InternalIdentity { this.isSecurityGroupEnabled = isSecurityGroupEnabled; this.vmId = nic.getInstanceId(); this.name = name; + this.ip6Cidr = nic.getIp6Cidr(); + this.ip6Gateway = nic.getIp6Gateway(); if (networkRate != null) { this.networkRate = networkRate; @@ -246,8 +251,9 @@ public class NicProfile implements InternalIdentity { this.strategy = strategy; } - public NicProfile(String requestedIp) { - this.requestedIp = requestedIp; + public NicProfile(String requestedIpv4, String requestedIpv6) { + this.requestedIpv4 = requestedIpv4; + this.requestedIpv6 = requestedIpv6; } public NicProfile() { @@ -273,8 +279,8 @@ public class NicProfile implements InternalIdentity { this.isSecurityGroupEnabled = enabled; } - public String getRequestedIp() { - return requestedIp; + public String getRequestedIpv4() { + return requestedIpv4; } public void deallocate() { @@ -302,4 +308,28 @@ public class NicProfile implements InternalIdentity { append(reservationId).append("-").append(ip4Address).append("-").append(broadcastUri).toString(); } + public String getIp6Gateway() { + return ip6Gateway; + } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public String getIp6Cidr() { + return ip6Cidr; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } + + public String getRequestedIpv6() { + return requestedIpv6; + } + + public void setRequestedIpv6(String requestedIpv6) { + this.requestedIpv6 = requestedIpv6; + } + } diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index fd9b0fc9477..fb574fa5848 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -51,6 +51,7 @@ import com.cloud.exception.StorageUnavailableException; import com.cloud.exception.VirtualMachineMigrationException; import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.Network.IpAddresses; import com.cloud.offering.ServiceOffering; import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; @@ -232,7 +233,7 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, String defaultIp, String keyboard) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIp, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** @@ -279,7 +280,7 @@ public interface UserVmService { * - name of the ssh key pair used to login to the virtual machine * @param requestedIps * TODO - * @param defaultIp + * @param defaultIps * TODO * @param accountName * - an optional account for the virtual machine. Must be used with domainId @@ -297,8 +298,8 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, - Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, - String defaultIp, String keyboard) + Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, + IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** @@ -343,8 +344,7 @@ public interface UserVmService { * - name of the ssh key pair used to login to the virtual machine * @param requestedIps * TODO - * @param defaultIp - * TODO + * @param defaultIps TODO * @param accountName * - an optional account for the virtual machine. Must be used with domainId * @param domainId @@ -361,7 +361,7 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, String defaultIp, String keyboard) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index e714ca42316..083b66f9a44 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -37,6 +37,7 @@ public class ApiConstants { public static final String DOMAIN_SUFFIX = "domainsuffix"; public static final String DNS_SEARCH_ORDER = "dnssearchorder"; public static final String CIDR = "cidr"; + public static final String IP6_CIDR = "ip6cidr"; public static final String CIDR_LIST = "cidrlist"; public static final String CLEANUP = "cleanup"; public static final String CLUSTER_ID = "clusterid"; @@ -63,6 +64,7 @@ public class ApiConstants { public static final String EMAIL = "email"; public static final String END_DATE = "enddate"; public static final String END_IP = "endip"; + public static final String END_IPV6 = "endipv6"; public static final String END_PORT = "endport"; public static final String ENTRY_TIME = "entrytime"; public static final String FETCH_LATEST = "fetchlatest"; @@ -72,6 +74,7 @@ public class ApiConstants { public static final String FORMAT = "format"; public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork"; public static final String GATEWAY = "gateway"; + public static final String IP6_GATEWAY = "ip6gateway"; public static final String GROUP = "group"; public static final String GROUP_ID = "groupid"; public static final String GUEST_CIDR_ADDRESS = "guestcidraddress"; @@ -89,6 +92,7 @@ public class ApiConstants { public static final String INTERNAL_DNS2 = "internaldns2"; public static final String INTERVAL_TYPE = "intervaltype"; public static final String IP_ADDRESS = "ipaddress"; + public static final String IP6_ADDRESS = "ip6address"; public static final String IP_ADDRESS_ID = "ipaddressid"; public static final String IS_ASYNC = "isasync"; public static final String IP_AVAILABLE = "ipavailable"; @@ -180,6 +184,7 @@ public class ApiConstants { public static final String SOURCE_ZONE_ID = "sourcezoneid"; public static final String START_DATE = "startdate"; public static final String START_IP = "startip"; + public static final String START_IPV6 = "startipv6"; public static final String START_PORT = "startport"; public static final String STATE = "state"; public static final String STATUS = "status"; diff --git a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java index 678b0e83857..5ec7cefb052 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java @@ -113,6 +113,18 @@ public class CreateNetworkCmd extends BaseCmd { description="the VPC network belongs to") private Long vpcId; + @Parameter(name=ApiConstants.START_IPV6, type=CommandType.STRING, description="the beginning IPv6 address in the IPv6 network range") + private String startIpv6; + + @Parameter(name=ApiConstants.END_IPV6, type=CommandType.STRING, description="the ending IPv6 address in the IPv6 network range") + private String endIpv6; + + @Parameter(name=ApiConstants.IP6_GATEWAY, type=CommandType.STRING, description="the gateway of the IPv6 network. Required " + + "for Shared networks and Isolated networks when it belongs to VPC") + private String ip6Gateway; + + @Parameter(name=ApiConstants.IP6_CIDR, type=CommandType.STRING, description="the CIDR of IPv6 network, must be at least /64") + private String ip6Cidr; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -207,6 +219,34 @@ public class CreateNetworkCmd extends BaseCmd { } } + public String getStartIpv6() { + if (startIpv6 == null) { + return null; + } + return startIpv6.toLowerCase(); + } + + public String getEndIpv6() { + if (endIpv6 == null) { + return null; + } + return endIpv6.toLowerCase(); + } + + public String getIp6Gateway() { + if (ip6Gateway == null) { + return null; + } + return ip6Gateway.toLowerCase(); + } + + public String getIp6Cidr() { + if (ip6Cidr == null) { + return null; + } + return ip6Cidr.toLowerCase(); + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -228,6 +268,10 @@ public class CreateNetworkCmd extends BaseCmd { @Override // an exception thrown by createNetwork() will be caught by the dispatcher. public void execute() throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException{ + if (getStartIpv6() != null && getStartIp() != null) { + throw new InvalidParameterValueException("Cannot support dualstack at this moment!"); + } + Network result = _networkService.createGuestNetwork(this); if (result != null) { NetworkResponse response = _responseGenerator.createNetworkResponse(result); diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index 567d171593f..70a263d06d2 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -55,6 +55,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddress; import com.cloud.network.Network; +import com.cloud.network.Network.IpAddresses; import com.cloud.offering.DiskOffering; import com.cloud.offering.ServiceOffering; import com.cloud.template.VirtualMachineTemplate; @@ -152,12 +153,15 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, description = "ip to network mapping. Can't be specified with networkIds parameter." + - " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].networkid=uuid - requests to use ip 10.10.10.11 in network id=uuid") + " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].ipv6=fc00:1234:5678::abcd&iptonetworklist[0].networkid=uuid - requests to use ip 10.10.10.11 in network id=uuid") private Map ipToNetworkList; @Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, description="the ip address for default vm's network") private String ipAddress; + @Parameter(name=ApiConstants.IP6_ADDRESS, type=CommandType.STRING, description="the ipv6 address for default vm's network") + private String ip6Address; + @Parameter(name=ApiConstants.KEYBOARD, type=CommandType.STRING, description="an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,fi,fr,fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us") private String keyboard; @@ -248,7 +252,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { public List getNetworkIds() { if (ipToNetworkList != null) { - if (networkIds != null || ipAddress != null) { + if (networkIds != null || ipAddress != null || getIp6Address() != null) { throw new InvalidParameterValueException("ipToNetworkMap can't be specified along with networkIds or ipAddress"); } else { List networks = new ArrayList(); @@ -275,13 +279,13 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { return startVm == null ? true : startVm; } - private Map getIpToNetworkMap() { - if ((networkIds != null || ipAddress != null) && ipToNetworkList != null) { + private Map getIpToNetworkMap() { + if ((networkIds != null || ipAddress != null || getIp6Address() != null) && ipToNetworkList != null) { throw new InvalidParameterValueException("NetworkIds and ipAddress can't be specified along with ipToNetworkMap parameter"); } - LinkedHashMap ipToNetworkMap = null; + LinkedHashMap ipToNetworkMap = null; if (ipToNetworkList != null && !ipToNetworkList.isEmpty()) { - ipToNetworkMap = new LinkedHashMap(); + ipToNetworkMap = new LinkedHashMap(); Collection ipsCollection = ipToNetworkList.values(); Iterator iter = ipsCollection.iterator(); while (iter.hasNext()) { @@ -298,13 +302,28 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { } } String requestedIp = (String) ips.get("ip"); - ipToNetworkMap.put(networkId, requestedIp); + String requestedIpv6 = (String) ips.get("ipv6"); + if (requestedIpv6 != null) { + requestedIpv6 = requestedIpv6.toLowerCase(); + } + if (requestedIpv6 != null) { + throw new InvalidParameterValueException("Cannot support specified IPv6 address!"); + } + IpAddresses addrs = new IpAddresses(requestedIp, requestedIpv6); + ipToNetworkMap.put(networkId, addrs); } } return ipToNetworkMap; } + public String getIp6Address() { + if (ip6Address == null) { + return null; + } + return ip6Address.toLowerCase(); + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -388,6 +407,10 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException{ try { + if (getIp6Address() != null) { + throw new InvalidParameterValueException("Cannot support specified IPv6 address!"); + } + //Verify that all objects exist before passing them to the service Account owner = _accountService.getActiveAccountById(getEntityOwnerId()); @@ -425,23 +448,24 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { } UserVm vm = null; + IpAddresses addrs = new IpAddresses(ipAddress, getIp6Address()); if (zone.getNetworkType() == NetworkType.Basic) { if (getNetworkIds() != null) { throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); } else { vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name, - displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), ipAddress, keyboard); + displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); } } else { if (zone.isSecurityGroupEnabled()) { vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), - owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), ipAddress, keyboard); + owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); } else { if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) { throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); } vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, - diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), ipAddress, keyboard); + diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); } } @@ -463,4 +487,5 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); } } + } diff --git a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java index 4c29f98bc94..2754182de82 100644 --- a/api/src/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NetworkResponse.java @@ -145,6 +145,12 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes @SerializedName(ApiConstants.TAGS) @Param(description="the list of resource tags associated with network", responseObject = ResourceTagResponse.class) private List tags; + @SerializedName(ApiConstants.IP6_GATEWAY) @Param(description="the gateway of IPv6 network") + private String ip6Gateway; + + @SerializedName(ApiConstants.IP6_CIDR) @Param(description="the cidr of IPv6 network") + private String ip6Cidr; + public void setId(String id) { this.id = id; } @@ -299,4 +305,12 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes public void setTags(List tags) { this.tags = tags; } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } } diff --git a/api/src/org/apache/cloudstack/api/response/NicResponse.java b/api/src/org/apache/cloudstack/api/response/NicResponse.java index 25131d277bd..a7d1a0d068e 100644 --- a/api/src/org/apache/cloudstack/api/response/NicResponse.java +++ b/api/src/org/apache/cloudstack/api/response/NicResponse.java @@ -67,6 +67,15 @@ public class NicResponse extends BaseResponse { @SerializedName("macaddress") @Param(description="true if nic is default, false otherwise") private String macAddress; + @SerializedName(ApiConstants.IP6_GATEWAY) @Param(description="the gateway of IPv6 network") + private String ip6Gateway; + + @SerializedName(ApiConstants.IP6_CIDR) @Param(description="the cidr of IPv6 network") + private String ip6Cidr; + + @SerializedName(ApiConstants.IP6_ADDRESS) @Param(description="the IPv6 address of network") + private String ip6Address; + public String getId() { return id; } @@ -120,6 +129,18 @@ public class NicResponse extends BaseResponse { this.macAddress = macAddress; } + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } + + public void setIp6Address(String ip6Address) { + this.ip6Address = ip6Address; + } + @Override public int hashCode() { final int prime = 31; @@ -146,5 +167,4 @@ public class NicResponse extends BaseResponse { return false; return true; } - } diff --git a/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java b/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java index 3dc46f96648..6c5c364cd8b 100644 --- a/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VlanIpRangeResponse.java @@ -81,6 +81,19 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Param(description="the physical network this belongs to") private String physicalNetworkId; + @SerializedName(ApiConstants.START_IPV6) @Param(description="the start ipv6 of the VLAN IP range") + private String startIpv6; + + @SerializedName(ApiConstants.END_IPV6) @Param(description="the end ipv6 of the VLAN IP range") + private String endIpv6; + + @SerializedName(ApiConstants.IP6_GATEWAY) @Param(description="the gateway of IPv6 network") + private String ip6Gateway; + + @SerializedName(ApiConstants.IP6_CIDR) @Param(description="the cidr of IPv6 network") + private String ip6Cidr; + + public void setId(String id) { this.id = id; } @@ -158,4 +171,24 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit public String getphysicalNetworkId() { return physicalNetworkId; } + + public String getStartIpv6() { + return startIpv6; + } + + public void setStartIpv6(String startIpv6) { + this.startIpv6 = startIpv6; + } + + public void setEndIpv6(String endIpv6) { + this.endIpv6 = endIpv6; + } + + public void setIp6Gateway(String ip6Gateway) { + this.ip6Gateway = ip6Gateway; + } + + public void setIp6Cidr(String ip6Cidr) { + this.ip6Cidr = ip6Cidr; + } } diff --git a/awsapi/src/com/cloud/bridge/model/CloudStackUserVO.java b/awsapi/src/com/cloud/bridge/model/CloudStackUserVO.java new file mode 100644 index 00000000000..fe1ec946941 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/model/CloudStackUserVO.java @@ -0,0 +1,49 @@ +// 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 com.cloud.bridge.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name="user") +public class CloudStackUserVO { + + @Column(name="api_key") + private String apiKey; + + @Column(name="secret_key") + private String secretKey; + + public String getApiKey() { + return apiKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + +} diff --git a/awsapi/src/com/cloud/bridge/persist/dao/CloudStackUserDao.java b/awsapi/src/com/cloud/bridge/persist/dao/CloudStackUserDao.java new file mode 100644 index 00000000000..f5d4aa14f57 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/persist/dao/CloudStackUserDao.java @@ -0,0 +1,26 @@ +// 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 com.cloud.bridge.persist.dao; + +import com.cloud.bridge.model.CloudStackUserVO; +import com.cloud.utils.db.GenericDao; + +public interface CloudStackUserDao extends GenericDao { + + public String getSecretKeyByAccessKey(String acessKey); + +} diff --git a/awsapi/src/com/cloud/bridge/persist/dao/CloudStackUserDaoImpl.java b/awsapi/src/com/cloud/bridge/persist/dao/CloudStackUserDaoImpl.java new file mode 100644 index 00000000000..061351930da --- /dev/null +++ b/awsapi/src/com/cloud/bridge/persist/dao/CloudStackUserDaoImpl.java @@ -0,0 +1,66 @@ +// 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 com.cloud.bridge.persist.dao; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; +import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; + +import com.cloud.bridge.model.CloudStackUserVO; +import com.cloud.bridge.util.EncryptionSecretKeyCheckerUtil; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; + +@Local(value={CloudStackUserDao.class}) +public class CloudStackUserDaoImpl extends GenericDaoBase implements CloudStackUserDao { + public static final Logger logger = Logger.getLogger(CloudStackUserDaoImpl.class); + + public CloudStackUserDaoImpl() {} + + @Override + public String getSecretKeyByAccessKey( String accessKey ) { + CloudStackUserVO user = null; + String cloudSecretKey = null; + + SearchBuilder searchByAccessKey = createSearchBuilder(); + searchByAccessKey.and("apiKey", searchByAccessKey.entity().getApiKey(), SearchCriteria.Op.EQ); + searchByAccessKey.done(); + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + txn.start(); + SearchCriteria sc = searchByAccessKey.create(); + sc.setParameters("apiKey", accessKey); + user = findOneBy(sc); + if ( user != null && user.getSecretKey() != null) { + // if the cloud db is encrypted, decrypt the secret_key returned by cloud db before signature generation + if( EncryptionSecretKeyCheckerUtil.useEncryption() ) { + StandardPBEStringEncryptor encryptor = EncryptionSecretKeyCheckerUtil.getEncryptor(); + cloudSecretKey = encryptor.decrypt( user.getSecretKey() ); + } else { + cloudSecretKey = user.getSecretKey(); + } + } + return cloudSecretKey; + } finally { + txn.close(); + } + } + +} diff --git a/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java b/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java index 15df24e62d2..57a32a48289 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java +++ b/awsapi/src/com/cloud/bridge/service/EC2RestServlet.java @@ -39,7 +39,6 @@ import java.util.List; import java.util.Properties; import java.util.UUID; -import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -98,8 +97,10 @@ import com.amazon.ec2.RunInstancesResponse; import com.amazon.ec2.StartInstancesResponse; import com.amazon.ec2.StopInstancesResponse; import com.amazon.ec2.TerminateInstancesResponse; +import com.cloud.bridge.model.CloudStackUserVO; import com.cloud.bridge.model.UserCredentialsVO; import com.cloud.bridge.persist.dao.CloudStackConfigurationDao; +import com.cloud.bridge.persist.dao.CloudStackUserDaoImpl; import com.cloud.bridge.persist.dao.OfferingDaoImpl; import com.cloud.bridge.persist.dao.UserCredentialsDaoImpl; import com.cloud.bridge.service.controller.s3.ServiceProvider; @@ -152,6 +153,7 @@ public class EC2RestServlet extends HttpServlet { private static final long serialVersionUID = -6168996266762804888L; @Inject UserCredentialsDaoImpl ucDao; @Inject OfferingDaoImpl ofDao; + @Inject CloudStackUserDaoImpl userDao; public static final Logger logger = Logger.getLogger(EC2RestServlet.class); @@ -686,46 +688,63 @@ public class EC2RestServlet extends HttpServlet { EC2request.setName( groupName[0] ); else { response.sendError(530, "Missing GroupName parameter" ); return; } + // -> not clear how many parameters there are until we fail to get IpPermissions.n.IpProtocol + int nCount = 1, mCount; + do { EC2IpPermission perm = new EC2IpPermission(); - String[] protocol = request.getParameterValues( "IpProtocol" ); + String[] protocol = request.getParameterValues( "IpPermissions." + nCount + ".IpProtocol" ); if ( null != protocol && 0 < protocol.length ) - perm.setProtocol( protocol[0] ); - else { response.sendError(530, "Missing IpProtocol parameter" ); return; } + perm.setProtocol( protocol[0]); + else break; - String[] fromPort = request.getParameterValues( "FromPort" ); - if ( null != fromPort && 0 < fromPort.length ) - perm.setProtocol( fromPort[0] ); - else { response.sendError(530, "Missing FromPort parameter" ); return; } + String[] fromPort = request.getParameterValues( "IpPermissions." + nCount + ".FromPort" ); + if ( null != fromPort && 0 < fromPort.length) + perm.setFromPort( Integer.parseInt( fromPort[0])); - String[] toPort = request.getParameterValues( "ToPort" ); - if ( null != toPort && 0 < toPort.length ) - perm.setProtocol( toPort[0] ); - else { response.sendError(530, "Missing ToPort parameter" ); return; } + String[] toPort = request.getParameterValues( "IpPermissions." + nCount + ".ToPort" ); + if ( null != toPort && 0 < toPort.length) + perm.setToPort( Integer.parseInt( toPort[0])); - String[] ranges = request.getParameterValues( "CidrIp" ); + // -> list: IpPermissions.n.IpRanges.m.CidrIp + mCount = 1; + do { + String[] ranges = request.getParameterValues( "IpPermissions." + nCount + ".IpRanges." + mCount + ".CidrIp" ); if ( null != ranges && 0 < ranges.length) - perm.addIpRange( ranges[0] ); - else { response.sendError(530, "Missing CidrIp parameter" ); return; } + perm.addIpRange( ranges[0]); + else break; + mCount++; + } while( true ); - String[] user = request.getParameterValues( "SourceSecurityGroupOwnerId" ); - if ( null == user || 0 == user.length) { - response.sendError(530, "Missing SourceSecurityGroupOwnerId parameter" ); - return; - } + // -> list: IpPermissions.n.Groups.m.UserId and IpPermissions.n.Groups.m.GroupName + mCount = 1; + do { + EC2SecurityGroup group = new EC2SecurityGroup(); - String[] name = request.getParameterValues( "SourceSecurityGroupName" ); - if ( null == name || 0 == name.length) { - response.sendError(530, "Missing SourceSecurityGroupName parameter" ); + String[] user = request.getParameterValues( "IpPermissions." + nCount + ".Groups." + mCount + ".UserId" ); + if ( null != user && 0 < user.length) + group.setAccount( user[0]); + else break; + + String[] name = request.getParameterValues( "IpPermissions." + nCount + ".Groups." + mCount + ".GroupName" ); + if ( null != name && 0 < name.length) + group.setName( name[0]); + else break; + + perm.addUser( group); + mCount++; + } while( true ); + + // -> multiple IP permissions can be specified per group name + EC2request.addIpPermission( perm); + nCount++; + } while( true ); + + if (1 == nCount) { + response.sendError(530, "At least one IpPermissions required" ); return; } - EC2SecurityGroup group = new EC2SecurityGroup(); - group.setAccount( user[0] ); - group.setName( name[0] ); - perm.addUser( group ); - EC2request.addIpPermission( perm ); - // -> execute the request RevokeSecurityGroupIngressResponse EC2response = EC2SoapServiceImpl.toRevokeSecurityGroupIngressResponse( ServiceProvider.getInstance().getEC2Engine().revokeSecurityGroup( EC2request )); @@ -753,10 +772,12 @@ public class EC2RestServlet extends HttpServlet { else break; String[] fromPort = request.getParameterValues( "IpPermissions." + nCount + ".FromPort" ); - if (null != fromPort && 0 < fromPort.length) perm.setProtocol( fromPort[0] ); + if ( null != fromPort && 0 < fromPort.length) + perm.setFromPort( Integer.parseInt( fromPort[0])); String[] toPort = request.getParameterValues( "IpPermissions." + nCount + ".ToPort" ); - if (null != toPort && 0 < toPort.length) perm.setProtocol( toPort[0] ); + if ( null != toPort && 0 < toPort.length) + perm.setToPort( Integer.parseInt( toPort[0])); // -> list: IpPermissions.n.IpRanges.m.CidrIp int mCount = 1; @@ -1723,17 +1744,13 @@ public class EC2RestServlet extends HttpServlet { } } - // [B] Use the cloudAccessKey to get the users secret key in the db - UserCredentialsVO cloudKeys = ucDao.getByAccessKey( cloudAccessKey ); - - if ( null == cloudKeys ) - { - logger.debug( cloudAccessKey + " is not defined in the EC2 service - call SetUserKeys" ); - response.sendError(404, cloudAccessKey + " is not defined in the EC2 service - call SetUserKeys" ); - return false; + // [B] Use the access key to get the users secret key from the cloud DB + cloudSecretKey = userDao.getSecretKeyByAccessKey( cloudAccessKey ); + if ( cloudSecretKey == null ) { + logger.debug("No Secret key found for Access key '" + cloudAccessKey + "' in the the EC2 service"); + throw new EC2ServiceException( ClientError.AuthFailure, "No Secret key found for Access key '" + cloudAccessKey + + "' in the the EC2 service" ); } - else cloudSecretKey = cloudKeys.getSecretKey(); - // [C] Verify the signature // -> getting the query-string in this way maintains its URL encoding @@ -1760,7 +1777,7 @@ public class EC2RestServlet extends HttpServlet { // exclude the signature string obviously. ;) if (paramName.equalsIgnoreCase("Signature")) continue; if (queryString == null) - queryString = paramName + "=" + request.getParameter(paramName); + queryString = paramName + "=" + URLEncoder.encode(request.getParameter(paramName), "UTF-8"); else queryString = queryString + "&" + paramName + "=" + URLEncoder.encode(request.getParameter(paramName), "UTF-8"); } diff --git a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java index 6ac8c97e666..b2451c6a0cb 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java +++ b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java @@ -1379,7 +1379,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { param7.setDnsName( "" ); param7.setReason( "" ); param7.setKeyName( inst.getKeyPairName()); - param7.setAmiLaunchIndex( "" ); + param7.setAmiLaunchIndex( null ); param7.setInstanceType( inst.getServiceOffering()); ProductCodesSetType param9 = new ProductCodesSetType(); @@ -1701,7 +1701,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { param7.setDnsName( "" ); param7.setReason( "" ); param7.setKeyName( inst.getKeyPairName()); - param7.setAmiLaunchIndex( "" ); + param7.setAmiLaunchIndex( null ); ProductCodesSetType param9 = new ProductCodesSetType(); ProductCodesSetItemType param10 = new ProductCodesSetItemType(); diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2AddressFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2AddressFilterSet.java index cb21fb2c0ae..1823b26218c 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2AddressFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2AddressFilterSet.java @@ -63,22 +63,21 @@ public class EC2AddressFilterSet { } - public EC2DescribeAddressesResponse evaluate( List addresses) throws ParseException { + public EC2DescribeAddressesResponse evaluate( EC2DescribeAddressesResponse response) throws ParseException { EC2DescribeAddressesResponse resultList = new EC2DescribeAddressesResponse(); boolean matched; + EC2Address[] addresses = response.getAddressSet(); EC2Filter[] filterSet = getFilterSet(); for ( EC2Address address : addresses ) { matched = true; - if (filterSet != null) { - for (EC2Filter filter : filterSet) { - if (!filterMatched(address, filter)) { - matched = false; - break; - } - } - } + for (EC2Filter filter : filterSet) { + if (!filterMatched(address, filter)) { + matched = false; + break; + } + } if (matched == true) resultList.addAddress(address); diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java index 9c0dc674577..8a5a733c4fb 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java @@ -320,7 +320,7 @@ public class EC2Engine extends ManagerBase { throw new EC2ServiceException(ClientError.InvalidGroup_NotFound, "Cannot find matching ruleid."); CloudStackInfoResponse resp = getApi().revokeSecurityGroupIngress(ruleId); - if (resp != null && resp.getId() != null) { + if (resp != null) { return resp.getSuccess(); } return false; @@ -351,7 +351,7 @@ public class EC2Engine extends ManagerBase { pair.setKeyValue(group.getAccount(), group.getName()); secGroupList.add(pair); } - CloudStackSecurityGroupIngress resp = null; + CloudStackSecurityGroup resp = null; if (ipPerm.getProtocol().equalsIgnoreCase("icmp")) { resp = getApi().authorizeSecurityGroupIngress(null, constructList(ipPerm.getIpRangeSet()), null, null, ipPerm.getIcmpCode(), ipPerm.getIcmpType(), ipPerm.getProtocol(), null, @@ -361,11 +361,14 @@ public class EC2Engine extends ManagerBase { ipPerm.getToPort().longValue(), null, null, ipPerm.getProtocol(), null, request.getName(), ipPerm.getFromPort().longValue(), secGroupList); } - if (resp != null && resp.getRuleId() != null) { - return true; - } + if (resp != null ){ + List ingressRules = resp.getIngressRules(); + for (CloudStackIngressRule ingressRule : ingressRules) + if (ingressRule.getRuleId() == null) return false; + } else { return false; } + } } catch(Exception e) { logger.error( "EC2 AuthorizeSecurityGroupIngress - ", e); throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); @@ -719,53 +722,22 @@ public class EC2Engine extends ManagerBase { throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); } } + /** - * Lists SSH KeyPairs on the systme + * Lists SSH KeyPairs on the system * * @param request * @return */ public EC2DescribeKeyPairsResponse describeKeyPairs( EC2DescribeKeyPairs request ) { try { - EC2KeyPairFilterSet filterSet = request.getKeyFilterSet(); - String[] keyNames = request.getKeyNames(); - List keyPairs = getApi().listSSHKeyPairs(null, null, null); - List keyPairsList = new ArrayList(); + EC2DescribeKeyPairsResponse response = listKeyPairs(request.getKeyNames()); + EC2KeyPairFilterSet kfs = request.getKeyFilterSet(); - if (keyPairs != null) { - // Let's trim the list of keypairs to only the ones listed in keyNames - List matchedKeyPairs = new ArrayList(); - if (keyNames != null && keyNames.length > 0) { - for (CloudStackKeyPair keyPair : keyPairs) { - boolean matched = false; - for (String keyName : keyNames) { - if (keyPair.getName().equalsIgnoreCase(keyName)) { - matched = true; - break; - } - } - if (matched) { - matchedKeyPairs.add(keyPair); - } - } - if (matchedKeyPairs.isEmpty()) { - throw new EC2ServiceException(ServerError.InternalError, "No matching keypairs found"); - } - }else{ - matchedKeyPairs = keyPairs; - } - - - // this should be reworked... converting from CloudStackKeyPairResponse to EC2SSHKeyPair is dumb - for (CloudStackKeyPair respKeyPair: matchedKeyPairs) { - EC2SSHKeyPair ec2KeyPair = new EC2SSHKeyPair(); - ec2KeyPair.setFingerprint(respKeyPair.getFingerprint()); - ec2KeyPair.setKeyName(respKeyPair.getName()); - ec2KeyPair.setPrivateKey(respKeyPair.getPrivatekey()); - keyPairsList.add(ec2KeyPair); - } - } - return filterSet.evaluate(keyPairsList); + if (kfs == null) + return response; + else + return kfs.evaluate(response); } catch(Exception e) { logger.error("EC2 DescribeKeyPairs - ", e); throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); @@ -850,24 +822,13 @@ public class EC2Engine extends ManagerBase { */ public EC2DescribeAddressesResponse describeAddresses( EC2DescribeAddresses request ) { try { - List addrList = getApi().listPublicIpAddresses(null, null, null, null, null, null, null, null, null); + EC2DescribeAddressesResponse response = listAddresses(request.getPublicIpsSet()); + EC2AddressFilterSet afs = request.getFilterSet(); - EC2AddressFilterSet filterSet = request.getFilterSet(); - List addressList = new ArrayList(); - if (addrList != null && addrList.size() > 0) { - for (CloudStackIpAddress addr: addrList) { - // remember, if no filters are set, request.inPublicIpSet always returns true - if (request.inPublicIpSet(addr.getIpAddress())) { - EC2Address ec2Address = new EC2Address(); - ec2Address.setIpAddress(addr.getIpAddress()); - if (addr.getVirtualMachineId() != null) - ec2Address.setAssociatedInstanceId(addr.getVirtualMachineId().toString()); - addressList.add(ec2Address); - } - } - } - - return filterSet.evaluate(addressList); + if (afs ==null) + return response; + else + return afs.evaluate(response); } catch(Exception e) { logger.error("EC2 DescribeAddresses - ", e); throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); @@ -2085,6 +2046,71 @@ public class EC2Engine extends ManagerBase { } } + private EC2DescribeKeyPairsResponse listKeyPairs( String[] keyNames ) throws Exception { + try { + EC2DescribeKeyPairsResponse keyPairSet = new EC2DescribeKeyPairsResponse(); + + List keyPairs = getApi().listSSHKeyPairs(null, null, null); + if (keyPairs != null && keyPairs.size() > 0) { + for (CloudStackKeyPair keyPair : keyPairs) { + boolean matched = false; + if (keyNames.length > 0) { + for (String keyName : keyNames) { + if (keyName.equalsIgnoreCase(keyPair.getName())) { + matched = true; + break; + } + } + } else matched = true; + if (!matched) continue; + EC2SSHKeyPair ec2KeyPair = new EC2SSHKeyPair(); + ec2KeyPair.setFingerprint(keyPair.getFingerprint()); + ec2KeyPair.setKeyName(keyPair.getName()); + ec2KeyPair.setPrivateKey(keyPair.getPrivatekey()); + + keyPairSet.addKeyPair(ec2KeyPair); + } + } + return keyPairSet; + } catch(Exception e) { + logger.error( "List Keypairs - ", e); + throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); + } + } + + private EC2DescribeAddressesResponse listAddresses(String[] addressNames) throws Exception { + try { + EC2DescribeAddressesResponse addressSet = new EC2DescribeAddressesResponse(); + + List addresses = getApi().listPublicIpAddresses(null, null, null, null, null, null, null, null, null); + if (addresses != null && addresses.size() > 0) { + for (CloudStackIpAddress address : addresses) { + boolean matched = false; + if ( addressNames.length > 0) { + for (String addressName : addressNames) { + if (address.getIpAddress().equalsIgnoreCase(addressName)) { + matched = true; + break; + } + } + } else matched = true; + + if (!matched) continue ; + + EC2Address ec2Address = new EC2Address(); + ec2Address.setIpAddress(address.getIpAddress()); + if (address.getVirtualMachineId() != null) + ec2Address.setAssociatedInstanceId(address.getVirtualMachineId().toString()); + addressSet.addAddress(ec2Address); + } + } + return addressSet; + } catch(Exception e) { + logger.error( "List Addresses - ", e); + throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); + } + } + /** * Convert ingress rule to EC2IpPermission records * diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2KeyPairFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2KeyPairFilterSet.java index 021487c7f71..2ad005b7dc2 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2KeyPairFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2KeyPairFilterSet.java @@ -62,14 +62,14 @@ public class EC2KeyPairFilterSet { } - public EC2DescribeKeyPairsResponse evaluate( List sampleList) throws ParseException { + public EC2DescribeKeyPairsResponse evaluate( EC2DescribeKeyPairsResponse response ) throws ParseException { EC2DescribeKeyPairsResponse resultList = new EC2DescribeKeyPairsResponse(); boolean matched; - EC2SSHKeyPair[] keypairSet = sampleList.toArray(new EC2SSHKeyPair[0]); + EC2SSHKeyPair[] keyPairSet = response.getKeyPairSet(); EC2Filter[] filterSet = getFilterSet(); - for (EC2SSHKeyPair keyPair : keypairSet) { + for (EC2SSHKeyPair keyPair : keyPairSet) { matched = true; for (EC2Filter filter : filterSet) { if (!filterMatched(keyPair, filter)) { diff --git a/awsapi/src/com/cloud/stack/CloudStackApi.java b/awsapi/src/com/cloud/stack/CloudStackApi.java index 52c2459e072..5a30ef22785 100644 --- a/awsapi/src/com/cloud/stack/CloudStackApi.java +++ b/awsapi/src/com/cloud/stack/CloudStackApi.java @@ -1115,9 +1115,9 @@ public class CloudStackApi { * @return * @throws Exception */ - public CloudStackSecurityGroupIngress authorizeSecurityGroupIngress(String account, String cidrList, String domainId, Long endPort, - String icmpCode, String icmpType, String protocol, String securityGroupId, String securityGroupName, Long startPort, - List userSecurityGroupList) throws Exception { + public CloudStackSecurityGroup authorizeSecurityGroupIngress(String account, String cidrList, String domainId, Long endPort, + String icmpCode, String icmpType, String protocol, String securityGroupId, String securityGroupName, Long startPort, + List userSecurityGroupList) throws Exception { CloudStackCommand cmd = new CloudStackCommand(ApiConstants.AUTHORIZE_SECURITY_GROUP_INGRESS); if (cmd != null) { if (account != null) cmd.setParam(ApiConstants.ACCOUNT, account); @@ -1139,7 +1139,8 @@ public class CloudStackApi { } } } - return _client.call(cmd, apiKey, secretKey, true, ApiConstants.AUTHORIZE_SECURITY_GROUP_INGRESS_RESPONSE, ApiConstants.SECURITY_GROUP, CloudStackSecurityGroupIngress.class); + return _client.call(cmd, apiKey, secretKey, true, ApiConstants.AUTHORIZE_SECURITY_GROUP_INGRESS_RESPONSE, + ApiConstants.SECURITY_GROUP, CloudStackSecurityGroup.class); } /** diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 13779251554..48ed9f57c13 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -49,7 +49,7 @@ - +