All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dasein.cloud.cloudstack.network.IpAddress Maven / Gradle / Ivy

Go to download

Implements the Dasein Cloud API for Cloud.com Cloudstack-based public and private clouds.

There is a newer version: 2015.10.5
Show newest version
/**
 * Copyright (C) 2009-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.cloudstack.network;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Future;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.dasein.cloud.CloudException;
import org.dasein.cloud.InternalException;
import org.dasein.cloud.OperationNotSupportedException;
import org.dasein.cloud.ProviderContext;
import org.dasein.cloud.Requirement;
import org.dasein.cloud.ResourceStatus;
import org.dasein.cloud.Tag;
import org.dasein.cloud.Taggable;
import org.dasein.cloud.cloudstack.CSCloud;
import org.dasein.cloud.cloudstack.CSException;
import org.dasein.cloud.cloudstack.CSMethod;
import org.dasein.cloud.cloudstack.CSVersion;
import org.dasein.cloud.cloudstack.Param;
import org.dasein.cloud.compute.VirtualMachine;
import org.dasein.cloud.identity.ServiceAction;
import org.dasein.cloud.network.AbstractIpAddressSupport;
import org.dasein.cloud.network.AddressType;
import org.dasein.cloud.network.IPVersion;
import org.dasein.cloud.network.IPAddressCapabilities;
import org.dasein.cloud.network.IpAddressSupport;
import org.dasein.cloud.network.IpForwardingRule;
import org.dasein.cloud.network.LoadBalancer;
import org.dasein.cloud.network.LoadBalancerSupport;
import org.dasein.cloud.network.Protocol;
import org.dasein.cloud.network.RawAddress;
import org.dasein.cloud.util.APITrace;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class IpAddress extends AbstractIpAddressSupport {
    static private final Logger logger = CSCloud.getLogger(IpAddress.class, "std");

    static final         String ASSOCIATE_IP_ADDRESS        = "associateIpAddress";
    static private final String CREATE_PORT_FORWARDING_RULE = "createPortForwardingRule";
    static private final String DISASSOCIATE_IP_ADDRESS     = "disassociateIpAddress";
    static private final String LIST_PORT_FORWARDING_RULES  = "listPortForwardingRules";
    static private final String LIST_PUBLIC_IP_ADDRESSES    = "listPublicIpAddresses";
    static private final String STOP_FORWARD                = "deletePortForwardingRule";

    public IpAddress(CSCloud provider) {
        super(provider);
    }

    public void assign(@Nonnull String addressId, @Nonnull String toServerId) throws InternalException, CloudException {
        throw new OperationNotSupportedException("Address assignment is not supported");
    }

    @Override
    public void assignToNetworkInterface(@Nonnull String addressId, @Nonnull String nicId) throws InternalException, CloudException {
        throw new OperationNotSupportedException("Network interfaces are not supported");
    }

    @Override
    public @Nonnull String forward(@Nonnull String addressId, int publicPort, @Nonnull Protocol protocol, int privatePort, @Nonnull String onServerId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "IpAddress.forward");
        try {
            VirtualMachine server = getProvider().getComputeServices().getVirtualMachineSupport().getVirtualMachine(onServerId);
            RawAddress privateIpAddress = null;

            if( server == null ) {
                throw new CloudException("No such server: " + onServerId);
            }
            RawAddress[] addresses = server.getPrivateAddresses();

            if( addresses != null && addresses.length > 0 ) {
                privateIpAddress = addresses[0];
            }
            if( privateIpAddress == null ) {
                throw new CloudException("Could not determine a private IP address for " + onServerId);
            }
            List params = new ArrayList();
            params.add(new Param("publicPort", String.valueOf(publicPort)));
            params.add(new Param("privatePort", String.valueOf(privatePort)));
            params.add(new Param("protocol", protocol.name()));
            params.add(new Param("virtualMachineId", onServerId));
            params.add(new Param("ipAddressId", addressId));

            Document doc = new CSMethod(getProvider()).get(CREATE_PORT_FORWARDING_RULE, params);

            getProvider().waitForJob(doc, "Assigning forwarding rule");
            for( IpForwardingRule rule : listRules(addressId) ) {
                if( rule.getPublicPort() == publicPort && rule.getPrivatePort() == privatePort && onServerId.equals(rule.getServerId()) && protocol.equals(rule.getProtocol()) && addressId.equals(rule.getAddressId()) ) {
                    return rule.getProviderRuleId();
                }
            }
            return null;
        }
        finally {
            APITrace.end();
        }
    }

    private transient volatile CSIPAddressCapabilities capabilities;
    @Nonnull
    @Override
    public IPAddressCapabilities getCapabilities() throws CloudException, InternalException {
        if( capabilities == null ) {
            capabilities = new CSIPAddressCapabilities(getProvider());
        }
        return capabilities;
    }

    private boolean isId() {
        return getProvider().getVersion().greaterThan(CSVersion.CS21);
    }

    @Override
    public @Nullable org.dasein.cloud.network.IpAddress getIpAddress(@Nonnull String addressId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "IpAddress.getIpAddress");
        try {
            try {
                CSMethod method = new CSMethod(getProvider());
                Document doc = method.get(LIST_PUBLIC_IP_ADDRESSES, new Param(isId() ? "id" : "ipAddress", addressId));
                HashMap loadBalancers = new HashMap();
                LoadBalancerSupport support = getProvider().getNetworkServices().getLoadBalancerSupport();
                LoadBalancer lb = (support == null ? null : support.getLoadBalancer(addressId));
                if( lb != null ) {
                    loadBalancers.put(addressId, lb);
                }
                NodeList matches = doc.getElementsByTagName("publicipaddress");
                for( int i = 0; i < matches.getLength(); i++ ) {
                    org.dasein.cloud.network.IpAddress addr = toAddress(matches.item(i), loadBalancers);
                    if( addr != null ) {
                        if( addr.getProviderIpAddressId().equals(addressId) ) {
                            return addr;
                        }
                    }
                }
                return null;
            }
            catch( CSException e ) {
                if( e.getHttpCode() == 431 ) {
                    return null;
                }
                throw e;
            }
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public boolean isSubscribed() throws CloudException, InternalException {
        APITrace.begin(getProvider(), "IpAddress.isSubscribed");
        try {
            new CSMethod(getProvider()).get(LIST_PUBLIC_IP_ADDRESSES, new Param("zoneId", getContext().getRegionId()));
            return true;
        }
        catch( CSException e ) {
            int code = e.getHttpCode();
            if( code == HttpServletResponse.SC_FORBIDDEN || code == 401 || code == 531 ) {
                return false;
            }
            throw e;
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public @Nonnull Iterable listIpPool(@Nonnull IPVersion version, boolean unassignedOnly) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "IpAddress.listIpPool");
        try {
            if( version.equals(IPVersion.IPV4) ) {
                HashMap loadBalancers = new HashMap();
                LoadBalancerSupport support = getProvider().getNetworkServices().getLoadBalancerSupport();

                if( support != null ) {
                    for( LoadBalancer lb : support.listLoadBalancers() ) {
                        loadBalancers.put(lb.getProviderLoadBalancerId(), lb);
                    }
                }
                CSMethod method = new CSMethod(getProvider());
                Document doc = method.get(LIST_PUBLIC_IP_ADDRESSES, new Param("zoneId", getContext().getRegionId()));
                ArrayList addresses = new ArrayList();

                int numPages = 1;
                NodeList nodes = doc.getElementsByTagName("count");
                Node n = nodes.item(0);
                if (n != null) {
                    String value = n.getFirstChild().getNodeValue().trim();
                    int count = Integer.parseInt(value);
                    numPages = count/500;
                    int remainder = count % 500;
                    if (remainder > 0) {
                        numPages++;
                    }
                }

                for (int page = 1; page <= numPages; page++) {
                    if (page > 1) {
                        String nextPage = String.valueOf(page);
                        doc = method.get(LIST_PUBLIC_IP_ADDRESSES,
                                new Param("zoneId", getContext().getRegionId()),
                                new Param("pagesize", "500"),
                                new Param("page", nextPage)
                        );
                    }
                    NodeList matches = doc.getElementsByTagName("publicipaddress");

                    for( int i=0; i> listIpPoolConcurrently(@Nonnull IPVersion version, boolean unassignedOnly) throws InternalException, CloudException {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public @Nonnull Iterable listIpPoolStatus(@Nonnull IPVersion version) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "IpAddress.listIpPoolStatus");
        try {
            if( !IPVersion.IPV4.equals(version) ) {
                return Collections.emptyList();
            }
            final Map loadBalancers = new HashMap();
            final LoadBalancerSupport support = getProvider().getNetworkServices().getLoadBalancerSupport();

            if( support != null ) {
                for( LoadBalancer lb : support.listLoadBalancers() ) {
                    loadBalancers.put(lb.getProviderLoadBalancerId(), lb);
                }
            }
            final CSMethod method = new CSMethod(getProvider());
            Document doc = method.get(LIST_PUBLIC_IP_ADDRESSES, new Param("zoneId", getContext().getRegionId()));
            List addresses = new ArrayList();

            int numPages = 1;
            NodeList nodes = doc.getElementsByTagName("count");
            Node n = nodes.item(0);
            if (n != null) {
                String value = n.getFirstChild().getNodeValue().trim();
                int count = Integer.parseInt(value);
                numPages = count/500;
                int remainder = count % 500;
                if (remainder > 0) {
                    numPages++;
                }
            }

            for (int page = 1; page <= numPages; page++) {
                if (page > 1) {
                    String nextPage = String.valueOf(page);
                    doc = method.get(LIST_PUBLIC_IP_ADDRESSES,
                            new Param("zoneId", getContext().getRegionId()),
                            new Param("pagesize", "500"),
                            new Param("page", nextPage));
                }
                NodeList matches = doc.getElementsByTagName("publicipaddress");

                for( int i=0; i listRules(@Nonnull String addressId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "IpAddress.listRules");
        try {
            ArrayList rules = new ArrayList();
            Param[] params;
            
            if( getProvider().getVersion().greaterThan(CSVersion.CS21) ) {
                params = new Param[] { new Param("ipaddressid", addressId) };                    
            }
            else {
                params = new Param[] { new Param("ipAddress", addressId) };
            }
            Document doc = new CSMethod(getProvider()).get(LIST_PORT_FORWARDING_RULES, params);
            
            if( doc == null ) {
                throw new CloudException("No such IP address: " + addressId);
            }
            NodeList matches = doc.getElementsByTagName("portforwardingrule");
            
            for( int i=0; i listSupportedIPVersions() throws CloudException, InternalException {
        return Collections.singletonList(IPVersion.IPV4);
    }

    @Override
    public @Nonnull String[] mapServiceAction(@Nonnull ServiceAction action) {
        return new String[0];
    }

    @Override
    public void releaseFromPool(@Nonnull String addressId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "IpAddress.releaseFromPool");
        try {
            CSMethod method = new CSMethod(getProvider());
        
            method.get(DISASSOCIATE_IP_ADDRESS, new Param(isId() ? "id" : "ipaddress", addressId));
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public void releaseFromServer(@Nonnull String addressId) throws InternalException, CloudException {
        throw new OperationNotSupportedException();
    }

    @Override
    public @Nonnull String request(@Nonnull AddressType typeOfAddress) throws InternalException, CloudException {
        if( typeOfAddress.equals(AddressType.PUBLIC) ) {
            return request(IPVersion.IPV4);
        }
        throw new OperationNotSupportedException("Private IP requests are not supported");
    }

    @Override
    public @Nonnull String request(@Nonnull IPVersion version) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "IpAddress.request");
        try {
            // TODO: review capabilities
            if( !version.equals(IPVersion.IPV4) ) {
                throw new OperationNotSupportedException("Only IPv4 is currently supported");
            }
            //if( isBasic() ) {
            Document doc = new CSMethod(getProvider()).get(ASSOCIATE_IP_ADDRESS,  new Param("zoneId", getContext().getRegionId()));
            // }
            //else {
            //  throw new
            //doc = method.get(method.buildUrl(ASSOCIATE_IP_ADDRESS,  new Param[] { new Param("zoneId", getProvider().getContext().getRegionId())  }))
            //}
            NodeList matches;

            if( getProvider().getVersion().greaterThan(CSVersion.CS21) ) {
                matches = doc.getElementsByTagName("id");
                if (matches.getLength() == 0) {
                    matches = doc.getElementsByTagName("jobid"); //4.1
                }
            }
            else {
                matches = doc.getElementsByTagName("ipaddress");
            }
            String id = null;
            if( matches.getLength() > 0 ) {
                id = matches.item(0).getFirstChild().getNodeValue();
            }
            if( id == null ) {
                throw new CloudException("Failed to request an IP address without error");
            }
            Document responseDoc = getProvider().waitForJob(doc, ASSOCIATE_IP_ADDRESS);
            if (responseDoc != null) {
                NodeList nodeList = responseDoc.getElementsByTagName("ipaddress");
                if (nodeList.getLength() > 0) {
                    Node ipAddress = nodeList.item(0);
                    NodeList attributes = ipAddress.getChildNodes();
                    for (int i = 0; i 0 ) {
                            value = attribute.getFirstChild().getNodeValue();
                        }
                        else {
                            value = null;
                        }
                        if (tmpname.equalsIgnoreCase("id")) {
                            id = value;
                            break;
                        }
                    }
                }
            }
            return id;
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public @Nonnull String requestForVLAN(@Nonnull IPVersion version) throws InternalException, CloudException {
        throw new OperationNotSupportedException("Not yet supported since CloudStack requires you to name the network");
    }

    @Override
    public @Nonnull String requestForVLAN(@Nonnull IPVersion version, @Nonnull String vlanId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "IpAddress.requestForVLAN");
        try {
            // TODO review capabilities
            if( !version.equals(IPVersion.IPV4) ) {
                throw new OperationNotSupportedException("Only IPv4 is currently supported");
            }
            CSMethod method = new CSMethod(getProvider());
            Document doc = method.get(ASSOCIATE_IP_ADDRESS,
                    new Param("zoneId", getContext().getRegionId()),
                    new Param("networkId", vlanId)
            );
            NodeList matches;

            if( getProvider().getVersion().greaterThan(CSVersion.CS21) ) {
                matches = doc.getElementsByTagName("id");
                if (matches.getLength() == 0) {
                    matches = doc.getElementsByTagName("jobid"); //4.1
                }
            }
            else {
                matches = doc.getElementsByTagName("ipaddress");
            }
            String id = null;
            if( matches.getLength() > 0 ) {
                id = matches.item(0).getFirstChild().getNodeValue();
            }
            if( id == null ) {
                throw new CloudException("Failed to request an IP address without error");
            }
            Document responseDoc = getProvider().waitForJob(doc, ASSOCIATE_IP_ADDRESS);
            if (responseDoc != null) {
                NodeList nodeList = responseDoc.getElementsByTagName("ipaddress");
                if (nodeList.getLength() > 0) {
                    Node ipAddress = nodeList.item(0);
                    NodeList attributes = ipAddress.getChildNodes();
                    for (int i = 0; i 0 ) {
                            value = attribute.getFirstChild().getNodeValue();
                        }
                        else {
                            value = null;
                        }
                        if (tmpname.equalsIgnoreCase("id")) {
                            id = value;
                            break;
                        }
                    }
                }
            }
            return id;
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public void stopForward(@Nonnull String ruleId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "IpAddress.stopForward");
        Logger logger = CSCloud.getLogger(IpAddress.class, "std");

        if( logger.isTraceEnabled() ) {
            logger.trace("enter - " + IpAddress.class.getName() + ".stopForward(" + ruleId + ")");
        }
        try {
            Document doc = new CSMethod(getProvider()).get(STOP_FORWARD, new Param("id", ruleId));
            getProvider().waitForJob(doc, STOP_FORWARD);
        }
        finally {
            if( logger.isTraceEnabled() ) {
                logger.trace("exit - " + IpAddress.class.getName() + ".stopForward()");
            }
            APITrace.end();
        }
    }

    @Override
    public boolean supportsVLANAddresses(@Nonnull IPVersion ofVersion) throws InternalException, CloudException {
        return IPVersion.IPV4.equals(ofVersion);
    }

    private @Nullable org.dasein.cloud.network.IpAddress toAddress(@Nullable Node node, @Nonnull Map loadBalancers) throws InternalException, CloudException {
        if( node == null ) {
            return null;
        }
        String regionId = getContext().getRegionId();

        if( regionId == null ) {
            throw new CloudException("No region was set for this request");
        }
        org.dasein.cloud.network.IpAddress address = new org.dasein.cloud.network.IpAddress();
        NodeList attributes = node.getChildNodes();
        
        address.setRegionId(regionId);
        address.setServerId(null);
        address.setProviderLoadBalancerId(null);
        address.setAddressType(AddressType.PUBLIC);
        for( int i=0; i 0 ) {
                value = n.getFirstChild().getNodeValue();
            }
            else {
                value = null;
            }
            if( name.equalsIgnoreCase("id") && value != null ) {
                address.setIpAddressId(value);
            }
            else if( name.equalsIgnoreCase("ipaddress") && value != null ) {
                //noinspection ConstantConditions
                if( address.getProviderIpAddressId() == null ) { // 2.1
                    address.setIpAddressId(value);
                }
                address.setAddress(value);
            }
            else if( name.equalsIgnoreCase("zoneid") && value != null ) {
                address.setRegionId(value);
            }
            else if( name.equalsIgnoreCase("virtualmachineid") ) {
                address.setServerId(value);
            }
            else if( name.equalsIgnoreCase("state") ) {
                if( value != null && !value.equalsIgnoreCase("allocated") ) {
                    return null;
                }
            }
            else if( name.equalsIgnoreCase("associatednetworkid") ) {
                if( value != null ) {
                    address.setForVlan(true);
                    address.setProviderVlanId(value);
                }
            }
        }
        LoadBalancer lb = loadBalancers.get(address.getRawAddress().getIpAddress());
            
        if( lb != null ) {
            address.setProviderLoadBalancerId(lb.getProviderLoadBalancerId());
        }
        if( address.getServerId() == null ) {
            for( VirtualMachine vm : getProvider().getComputeServices().getVirtualMachineSupport().listVirtualMachines() ) {
                RawAddress[] addrs = vm.getPublicAddresses();
                
                for( RawAddress addr : addrs ) {
                    if( addr.getIpAddress().equals(address.getRawAddress().getIpAddress()) ) {
                        address.setServerId(vm.getProviderVirtualMachineId());
                    }
                }
            }
        }
        return address;
    }

    private @Nullable ResourceStatus toStatus(@Nullable Node node, @Nonnull Map loadBalancers) throws InternalException, CloudException {
        if( node == null ) {
            return null;
        }
        NodeList attributes = node.getChildNodes();
        String addressId = null, address = null;
        Boolean available = null;
        boolean hasState = false;

        for( int i=0; i 0 ) {
                value = n.getFirstChild().getNodeValue();
            }
            else {
                value = null;
            }
            if( name.equalsIgnoreCase("id") && value != null ) {
                addressId = value;
            }
            else if( name.equalsIgnoreCase("ipaddress") && value != null ) {
                address = value;
            }
            else if( name.equalsIgnoreCase("virtualmachineid") ) {
                available = (value != null && !value.equals(""));
            }
            else if( name.equalsIgnoreCase("state") ) {
                if( value != null && !value.equalsIgnoreCase("allocated") ) {
                    return null;
                }
                hasState = true;
            }
            if( addressId != null && address != null && available != null && hasState ) {
                break;
            }
        }
        if( addressId == null ) {
            return null;
        }
        if( address != null ) {
            LoadBalancer lb = loadBalancers.get(address);

            if( lb != null ) {
                available = false;
            }
        }
        if( available == null ) {
            available = true;
        }
        return new ResourceStatus(addressId, available);
    }

    @Override
    public void setTags(@Nonnull String addressId, @Nonnull Tag... tags) throws CloudException, InternalException {
    	setTags(new String[] { addressId }, tags);
    }

    @Override
    public void setTags(@Nonnull String[] addressIds, @Nonnull Tag... tags) throws CloudException, InternalException {
    	APITrace.begin(getProvider(), "IpAddress.setTags");
    	try {
    		removeTags(addressIds);
    		getProvider().createTags(addressIds, "PublicIpAddress", tags);
    	}
    	finally {
    		APITrace.end();
    	}
    }

    @Override
    public void updateTags(@Nonnull String addressId, @Nonnull Tag... tags) throws CloudException, InternalException {
    	updateTags(new String[] { addressId }, tags);
    }

    @Override
    public void updateTags(@Nonnull String[] addressIds, @Nonnull Tag... tags) throws CloudException, InternalException {
    	APITrace.begin(getProvider(), "IpAddress.updateTags");
    	try {
    		getProvider().updateTags(addressIds, "PublicIpAddress", tags);
    	}
    	finally {
    		APITrace.end();
    	}
    }

    @Override
    public void removeTags(@Nonnull String addressId, @Nonnull Tag... tags)
    		throws CloudException, InternalException {
    	removeTags(new String[] { addressId }, tags);
    }

    @Override
    public void removeTags(@Nonnull String[] addressIds, @Nonnull Tag... tags) throws CloudException, InternalException {
    	APITrace.begin(getProvider(), "IpAddress.removeTags");
    	try {
    		getProvider().removeTags(addressIds, "PublicIpAddress", tags);
    	}
    	finally {
    		APITrace.end();
    	}
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy