Java tutorial
/** * Copyright (C) 2013-2015 Dell, Inc * * ==================================================================== * Licensed 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.dasein.cloud.azure.network; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Predicate; import org.apache.log4j.Logger; import org.bouncycastle.util.IPAddress; import org.dasein.cloud.*; import org.dasein.cloud.azure.Azure; import org.dasein.cloud.azure.AzureMethod; import org.dasein.cloud.azure.compute.vm.AzureRoleDetails; import org.dasein.cloud.azure.network.model.PersistentVMRoleModel; import org.dasein.cloud.compute.VirtualMachine; import org.dasein.cloud.identity.ServiceAction; import org.dasein.cloud.network.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.xml.bind.JAXBException; import java.util.ArrayList; import java.util.Collections; import java.util.Locale; import java.util.concurrent.Future; /** * Created by Vlad_Munthiu on 7/31/2014. */ public class AzureIpAddressSupport extends AbstractIpAddressSupport<Azure> { static private final Logger logger = Logger.getLogger(AzureIpAddressSupport.class); static private final Logger wire = Azure.getWireLogger(AzureIpAddressSupport.class); private Azure provider; public static final String RESOURCE_ROLE = "/services/hostedservices/%s/deployments/%s/roles/%s"; public AzureIpAddressSupport(Azure provider) { super(provider); this.provider = provider; } /** * Assigns the specified address to the target server. This method should be called only if * {@link #isAssigned(AddressType)} for the specified address's address type is <code>true</code>. * If it is not, you will see the {@link RuntimeException} {@link org.dasein.cloud.OperationNotSupportedException} * thrown. * * @param addressId the unique identifier of the address to be assigned * @param serverId the unique ID of the server to which the address is being assigned * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud * @throws org.dasein.cloud.OperationNotSupportedException this cloud provider does not support address assignment of the specified address type */ @Override public void assign(@Nonnull String addressId, @Nonnull String serverId) throws InternalException, CloudException { throw new OperationNotSupportedException("AzureIpAddressSupport#assign not supported"); } /** * Assigns the specified address to the specified network interface. * * @param addressId the unique ID of the IP address to assign * @param nicId the unique ID of the network interface to which the address is being assigned * @throws org.dasein.cloud.InternalException an error occurred locally while performing the assignment * @throws org.dasein.cloud.CloudException an error occurred in the cloud provider while performing the assignment */ @Override public void assignToNetworkInterface(@Nonnull String addressId, @Nonnull String nicId) throws InternalException, CloudException { throw new OperationNotSupportedException("AzureIpAddressSupport#assignToNetworkInterface not supported"); } /** * Forwards the specified public IP address traffic on the specified public port over to the * specified private port on the specified server. If the server goes away, you will generally * still have traffic being forwarded to the private IP formally associated with the server, so * it is best to stop forwarding before terminating a server. * <p> * You should check {@link #isForwarding()} before calling this method. The implementation should * throw a {@link org.dasein.cloud.OperationNotSupportedException} {@link RuntimeException} if the underlying * cloud does not support IP address forwarding. * </p> * * @param addressId the unique ID of the public IP address to be forwarded * @param publicPort the public port of traffic to be forwarded * @param protocol the network protocol being forwarded (not all clouds support ICMP) * @param privatePort the private port on the server to which traffic should be forwarded * @param onServerId the unique ID of the server to which traffic is to be forwarded * @return the rule ID for the forwarding rule that is created * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud * @throws org.dasein.cloud.OperationNotSupportedException this cloud provider does not support address forwarding */ @Nonnull @Override public String forward(@Nonnull String addressId, int publicPort, @Nonnull Protocol protocol, int privatePort, @Nonnull String onServerId) throws InternalException, CloudException { PersistentVMRoleModel persistentVMRoleModel = getVMRole(onServerId); if (persistentVMRoleModel == null) throw new InternalException("Cannot find Azure virtual machine with id: " + onServerId); PersistentVMRoleModel.InputEndpoint inputEndpoint = new PersistentVMRoleModel.InputEndpoint(); inputEndpoint.setLocalPort(String.valueOf(privatePort)); inputEndpoint.setPort(String.valueOf(publicPort)); inputEndpoint.setProtocol(protocol.toString()); inputEndpoint.setName(protocol.toString() + String.valueOf(publicPort)); if (persistentVMRoleModel.getConfigurationSets().get(0).getInputEndpoints() == null) persistentVMRoleModel.getConfigurationSets().get(0) .setInputEndpoints(new ArrayList<PersistentVMRoleModel.InputEndpoint>()); persistentVMRoleModel.getConfigurationSets().get(0).getInputEndpoints().add(inputEndpoint); updateVMRole(onServerId, persistentVMRoleModel); return inputEndpoint.getName(); } /** * Provides access to meta-data about IP Address capabilities in the current region of this cloud. * * @return a description of the features supported by this region of this cloud * @throws org.dasein.cloud.InternalException an error occurred within the Dasein Cloud API implementation * @throws org.dasein.cloud.CloudException an error occurred within the cloud provider */ @Nonnull @Override public IPAddressCapabilities getCapabilities() throws CloudException, InternalException { return new AzureIpAddressCapabilities(this.provider); } /** * Provides the {@link org.dasein.cloud.network.IpAddress} identified by the specified unique address ID. * * @param addressId the unique ID of the IP address being requested * @return the matching {@link org.dasein.cloud.network.IpAddress} * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud */ @Nullable @Override public IpAddress getIpAddress(@Nonnull String addressId) throws InternalException, CloudException { throw new OperationNotSupportedException("AzureIpAddressSupport#getIpAddress not supported"); } /** * The cloud provider-specific term for an IP address. It's hard to fathom what other * than "IP address" anyone could use. * * @param locale the locale into which the term should be translated * @return the cloud provider-specific term for an IP address * @deprecated use {@link org.dasein.cloud.network.IPAddressCapabilities#getProviderTermForIpAddress(java.util.Locale)} */ @Nonnull @Override public String getProviderTermForIpAddress(@Nonnull Locale locale) { return ""; } /** * Indicates whether you need to specify which VLAN you are tying a static IP address to when creating an * IP address for use in a VLAN. REQUIRED means you must specify the VLAN, OPTIONAL means you may, and NONE * means you do not specify a VLAN. * * @return the level of requirement for specifying a VLAN when creating a VLAN IP address * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @deprecated use {@link org.dasein.cloud.network.IPAddressCapabilities#identifyVlanForVlanIPRequirement()} */ @Nonnull @Override public Requirement identifyVlanForVlanIPRequirement() throws CloudException, InternalException { throw new OperationNotSupportedException( "AzureIpAddressSupport#identifyVlanForVlanIPRequirement not supported"); } /** * Indicates whether the underlying cloud supports the assignment of addresses of the specified * type. * * @param type the type of address being checked (public or private) * @return <code>true</code> if addresses of the specified type are assignable to servers * @deprecated use {@link #isAssigned(org.dasein.cloud.network.IPVersion)} */ @Override public boolean isAssigned(@Nonnull AddressType type) { return false; } /** * Indicates whether the underlying cloud supports the assignment of addresses of the specified version * * @param version the IP version being checked * @return true if the addresses of the specified version are assignable to cloud resources for public routing * @throws org.dasein.cloud.CloudException an error occurred with the cloud provider determining support * @throws org.dasein.cloud.InternalException a local error occurred determining support * @deprecated use {@link org.dasein.cloud.network.IPAddressCapabilities#isAssigned(org.dasein.cloud.network.IPVersion)} */ @Override public boolean isAssigned(@Nonnull IPVersion version) throws CloudException, InternalException { return false; } /** * When addresses are assignable, they may be assigned at launch, post-launch, or both. * {@link org.dasein.cloud.compute.VirtualMachineCapabilities#identifyStaticIPRequirement()} will tell you what must be done * at launch time. This method indicates whether or not assignable IPs may be assigned after launch. This * method should never return true when {@link #isAssigned(org.dasein.cloud.network.IPVersion)} returns false. * * @param version the IP version being checked * @return true if IP addresses of the specified version can be assigned post launch * @throws org.dasein.cloud.CloudException an error occurred with the cloud provider determining support * @throws org.dasein.cloud.InternalException a local error occurred determining support * @deprecated use {@link org.dasein.cloud.network.IPAddressCapabilities#isAssignablePostLaunch(org.dasein.cloud.network.IPVersion)} */ @Override public boolean isAssignablePostLaunch(@Nonnull IPVersion version) throws CloudException, InternalException { return false; } /** * Indicates whether the underlying cloud supports the forwarding individual port traffic on * public IP addresses to hosts private IPs. These addresses may also be used for load * balancers in some clouds as well. * * @return <code>true</code> if public IPs may be forwarded on to private IPs * @deprecated use {@link #isForwarding(org.dasein.cloud.network.IPVersion)} */ @Override public boolean isForwarding() { return true; } /** * Indicates whether the underlying cloud supports the forwarding of traffic on individual ports * targeted to addresses of the specified version on to resources in the cloud. * * @param version the IP version being checked * @return true if forwarding is supported * @throws org.dasein.cloud.CloudException an error occurred with the cloud provider determining support * @throws org.dasein.cloud.InternalException a local error occurred determining support * @deprecated use {@link org.dasein.cloud.network.IPAddressCapabilities#isForwarding(org.dasein.cloud.network.IPVersion)} */ @Override public boolean isForwarding(IPVersion version) throws CloudException, InternalException { return true; } /** * Indicates whether the underlying cloud allows you to make programmatic requests for * new IP addresses of the specified type * * @param type the type of address being checked (public or private) * @return <code>true</code> if there are programmatic mechanisms for allocating new IPs of the specified type * @deprecated use {@link #isRequestable(org.dasein.cloud.network.IPVersion)} */ @Override public boolean isRequestable(@Nonnull AddressType type) { return false; } /** * Indicates whether or not you can request static IP addresses of the specified Internet Protocol version. * * @param version the IP version you may want to request * @return true if you can make requests from the cloud provider to add addresses of this version to your pool * @throws org.dasein.cloud.CloudException an error occurred with the cloud provider while determining if your account has support * @throws org.dasein.cloud.InternalException a local exception occurred while determining support * @deprecated use {@link org.dasein.cloud.network.IPAddressCapabilities#isRequestable(org.dasein.cloud.network.IPVersion)} */ @Override public boolean isRequestable(@Nonnull IPVersion version) throws CloudException, InternalException { return false; } /** * Indicates whether this account is subscribed to leverage IP address services in the * target cloud. * * @return <code>true</code> if the account holder is subscribed * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud */ @Override public boolean isSubscribed() throws CloudException, InternalException { return false; } /** * Lists all (or unassigned) private IP addresses from the account holder's private IP address * pool. This method is safe to call even if private IP forwarding is not supported. It will * simply return {@link java.util.Collections#emptyList()}. * * @param unassignedOnly indicates that only unassigned addresses are being sought * @return all private IP addresses or the unassigned ones from the pool * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud * @throws OperationNotSupportedException the requested version is not supported * @deprecated private IP pools no longer make sense, use the {@link org.dasein.cloud.network.VLANSupport} class */ @Nonnull @Override public Iterable<IpAddress> listPrivateIpPool(boolean unassignedOnly) throws InternalException, CloudException { return Collections.emptyList(); } /** * Lists all (or unassigned) public IP addresses from the account holder's public IP address * pool. This method is safe to call even if public IP forwarding is not supported. It will * simply return {@link java.util.Collections#emptyList()}. * * @param unassignedOnly indicates that only unassigned addresses are being sought * @return all public IP addresses or the unassigned ones from the pool * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud * @throws OperationNotSupportedException the requested version is not supported * @deprecated use {@link #listIpPool(org.dasein.cloud.network.IPVersion, boolean)} */ @Nonnull @Override public Iterable<IpAddress> listPublicIpPool(boolean unassignedOnly) throws InternalException, CloudException { return Collections.emptyList(); } /** * Lists all IP addresses of the specified IP version that are allocated to the account holder's IP address pool. If * the specified version is not supported, an empty list should be returned. * * @param version the version of the IP protocol for which you are looking for IP addresses * @param unassignedOnly show only IP addresses that have yet to be assigned to cloud resources * @return all matching IP addresses from the IP address pool * @throws org.dasein.cloud.InternalException a local error occurred loading the IP addresses * @throws org.dasein.cloud.CloudException an error occurred with the cloud provider while requesting the IP addresses */ @Nonnull @Override public Iterable<IpAddress> listIpPool(@Nonnull IPVersion version, boolean unassignedOnly) throws InternalException, CloudException { return Collections.emptyList(); } /** * Lists all IP addresses of the specified IP version that are allocated to the account holder's IP address pool. If * the specified version is not supported, an empty list should be returned. This method implements a callable so * it can be called concurrently. * * @param version the version of the IP protocol for which you are looking for IP addresses * @param unassignedOnly show only IP addresses that have yet to be assigned to cloud resources * @return all matching IP addresses from the IP address pool * @throws org.dasein.cloud.InternalException a local error occurred loading the IP addresses * @throws org.dasein.cloud.CloudException an error occurred with the cloud provider while requesting the IP addresses */ @Nonnull @Override public Future<Iterable<IpAddress>> listIpPoolConcurrently(@Nonnull IPVersion version, boolean unassignedOnly) throws InternalException, CloudException { return null; } /** * Lists the status of all IP addresses of the specified IP version that are allocated to the account holder's IP * address pool. If the specified version is not supported, an empty list should be returned. * * @param version the version of the IP protocol for which you are looking for IP addresses * @return the status of all matching IP addresses from the IP address pool * @throws org.dasein.cloud.InternalException a local error occurred loading the IP addresses * @throws org.dasein.cloud.CloudException an error occurred with the cloud provider while requesting the IP addresses */ @Nonnull @Override public Iterable<ResourceStatus> listIpPoolStatus(@Nonnull IPVersion version) throws InternalException, CloudException { return Collections.emptyList(); } /** * Lists the IP forwarding rules associated with the specified public IP address. This method * is safe to call even when requested on a private IP address or when IP forwarding is not supported. * In those situations, {@link java.util.Collections#emptyList()} will be returned. * * @param serverId the unique ID of the virtual machine whose forwarding rules will be sought * @return all IP forwarding rules for the specified IP address * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud */ @Override public @Nonnull Iterable<IpForwardingRule> listRulesForServer(@Nonnull String serverId) throws InternalException, CloudException { PersistentVMRoleModel persistentVMRoleModel = getVMRole(serverId); if (persistentVMRoleModel == null) throw new InternalException("Cannot find Azure virtual machine with id: " + serverId); ArrayList<IpForwardingRule> rules = new ArrayList<IpForwardingRule>(); if (persistentVMRoleModel.getConfigurationSets().get(0).getInputEndpoints() != null) { for (PersistentVMRoleModel.InputEndpoint endpoint : persistentVMRoleModel.getConfigurationSets().get(0) .getInputEndpoints()) { IpForwardingRule rule = new IpForwardingRule(); rule.setProviderRuleId(endpoint.getName()); rule.setPublicPort(Integer.parseInt(endpoint.getPort())); rule.setPrivatePort(Integer.parseInt(endpoint.getLocalPort())); rule.setServerId(serverId); rules.add(rule); } } return rules; } /** * Lists all IP protocol versions supported for static IP addresses in this cloud. * * @return a list of supported versions * @throws org.dasein.cloud.CloudException an error occurred checking support for IP versions with the cloud provider * @throws org.dasein.cloud.InternalException a local error occurred preparing the supported version * @deprecated use {@link org.dasein.cloud.network.IPAddressCapabilities#listSupportedIPVersions()} */ @Nonnull @Override public Iterable<IPVersion> listSupportedIPVersions() throws CloudException, InternalException { return Collections.emptyList(); } /** * When a cloud allows for programmatic requesting of new IP addresses, you may also programmaticall * release them ({@link #isRequestable(org.dasein.cloud.network.AddressType)}). This method will release the specified IP * address from your pool and you will no longer be able to use it for assignment or forwarding. * * @param addressId the unique ID of the address to be release * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud * @throws org.dasein.cloud.OperationNotSupportedException this cloud provider does not support address requests */ @Override public void releaseFromPool(@Nonnull String addressId) throws InternalException, CloudException { throw new OperationNotSupportedException("AzureIpAddressSupport#releaseFromPool not supported"); } /** * Releases an IP address assigned to a server so that it is unassigned in the address pool. * You should call this method only when {@link #isAssigned(org.dasein.cloud.network.AddressType)} is <code>true</code> * for addresses of the target address's type. * * @param addressId the address ID to release from its server assignment * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud * @throws org.dasein.cloud.OperationNotSupportedException this cloud provider does not support address assignment for addresses of the specified type */ @Override public void releaseFromServer(@Nonnull String addressId) throws InternalException, CloudException { throw new OperationNotSupportedException("AzureIpAddressSupport#releaseFromServer not supported"); } /** * When requests for new IP addresses may be handled programmatically, this method allocates * a new IP address of the specified type. You should call it only if * {@link #isRequestable(org.dasein.cloud.network.AddressType)} is <code>true</code> for the address's type. * * @param typeOfAddress the type of address being requested * @return the newly allocated IP address * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud * @throws org.dasein.cloud.OperationNotSupportedException this cloud provider does not support address requests * @deprecated use {@link #request(org.dasein.cloud.network.IPVersion)} */ @Nonnull @Override public String request(@Nonnull AddressType typeOfAddress) throws InternalException, CloudException { return ""; } /** * Requests an IP address of the specified version for the flat (non-VLAN) network space. * * @param version the IP version of the address to be requested * @return the unique ID of the newly provisioned static IP address * @throws org.dasein.cloud.InternalException a local error occurred while preparing the request * @throws org.dasein.cloud.CloudException an error occurred with the cloud while provisioning the new address */ @Nonnull @Override public String request(@Nonnull IPVersion version) throws InternalException, CloudException { return ""; } /** * Requests a public IP address that may be used with a VLAN. This version may be used only when * {@link #identifyVlanForVlanIPRequirement()} is not {@link org.dasein.cloud.Requirement#REQUIRED}. * * @param version the IP version of the address to be requested * @return the unique ID of a newly provisioned public IP address * @throws org.dasein.cloud.InternalException an error occurred locally while attempting to provision the IP address * @throws org.dasein.cloud.CloudException an error occurred in the cloud provider while provisioning the IP address * @throws OperationNotSupportedException either VLAN IPs are not supported or they must be explicitly associated with a VLAN */ @Nonnull @Override public String requestForVLAN(@Nonnull IPVersion version) throws InternalException, CloudException { return ""; } /** * Requests a public IP address that must be used with a specific VLAN. This version may be used only when * {@link #identifyVlanForVlanIPRequirement()} is not {@link org.dasein.cloud.Requirement#NONE}. * * @param version the IP version of the address to be requested * @param vlanId the unique ID of the VLAN to which the IP address will be assigned * @return the unique ID of a newly provisioned public IP address * @throws org.dasein.cloud.InternalException an error occurred locally while attempting to provision the IP address * @throws org.dasein.cloud.CloudException an error occurred in the cloud provider while provisioning the IP address * @throws OperationNotSupportedException either VLAN IPs are not supported or they cannot be explicitly associated with a VLAN */ @Nonnull @Override public String requestForVLAN(@Nonnull IPVersion version, @Nonnull String vlanId) throws InternalException, CloudException { return ""; } /** * Removes the specified forwarding rule from the address with which it is associated. * * @param ruleId the rule to be removed * @throws org.dasein.cloud.InternalException an internal error occurred inside the Dasein Cloud implementation * @throws org.dasein.cloud.CloudException an error occurred processing the request in the cloud * @throws org.dasein.cloud.OperationNotSupportedException this cloud provider does not support address forwarding */ @Override public void stopForwardToServer(@Nonnull final String ruleId, @Nonnull String serverId) throws InternalException, CloudException { PersistentVMRoleModel persistentVMRoleModel = getVMRole(serverId); if (persistentVMRoleModel == null) throw new InternalException("Cannot find Azure virtual machine with id: " + serverId); CollectionUtils.filter(persistentVMRoleModel.getConfigurationSets().get(0).getInputEndpoints(), new Predicate() { @Override public boolean evaluate(Object object) { return ((PersistentVMRoleModel.InputEndpoint) object).getName() .equalsIgnoreCase(ruleId) == false; } }); updateVMRole(serverId, persistentVMRoleModel); } /** * Indicates whether or not IP addresses can be allocated for VLAN use. Only makes sense when the cloud * actually supports VLANS. * * @param ofVersion the version of public IP address that might be routed to a VLAN resource * @return true if an IP address may be allocated for use by VLANs * @throws org.dasein.cloud.InternalException a local error occurred determining support * @throws org.dasein.cloud.CloudException an error occurred with the cloud provider in determining support * @deprecated use {@link org.dasein.cloud.network.IPAddressCapabilities#supportsVLANAddresses(org.dasein.cloud.network.IPVersion)} */ @Override public boolean supportsVLANAddresses(@Nonnull IPVersion ofVersion) throws InternalException, CloudException { return false; } /** * Maps the specified Dasein Cloud service action to an identifier specific to an underlying cloud. If there is * no mapping that makes any sense, the method will return an empty array. * * @param action the Dasein Cloud service action * @return a list of cloud-specific IDs (e.g. iam:ListGroups) representing an action with this cloud provider */ @Nonnull @Override public String[] mapServiceAction(@Nonnull ServiceAction action) { return new String[0]; } private void updateVMRole(String vmId, PersistentVMRoleModel persistentVMRoleModel) throws CloudException, InternalException { AzureRoleDetails roleDetails = AzureRoleDetails.fromString(vmId); try { new AzureMethod(this.provider).put(String.format(RESOURCE_ROLE, roleDetails.getServiceName(), roleDetails.getDeploymentName(), roleDetails.getRoleName()), persistentVMRoleModel); } catch (JAXBException e) { logger.error(e.getMessage()); throw new InternalException(e); } } private PersistentVMRoleModel getVMRole(String vmId) { AzureRoleDetails roleDetails = AzureRoleDetails.fromString(vmId); try { return new AzureMethod(this.provider).get(PersistentVMRoleModel.class, String.format(RESOURCE_ROLE, roleDetails.getServiceName(), roleDetails.getDeploymentName(), roleDetails.getRoleName())); } catch (Exception ex) { return null; } } }