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

org.dasein.cloud.cloudstack.CSMethod 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;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.SignatureException;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.TreeSet;

import javax.annotation.Nonnull;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.dasein.cloud.CloudErrorType;
import org.dasein.cloud.CloudException;
import org.dasein.cloud.ContextRequirements;
import org.dasein.cloud.InternalException;
import org.dasein.cloud.ProviderContext;
import org.dasein.cloud.util.APITrace;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.SAXException;

public class CSMethod {
    static public class ParsedError {
        public int code;
        public String message;
    }
    
    static public final String CREATE_KEYPAIR = "createSSHKeyPair";
    static public final String DELETE_KEYPAIR = "deleteSSHKeyPair";
    static public final String LIST_KEYPAIRS  = "listSSHKeyPairs";

    private CSCloud provider;
    
    public CSMethod(@Nonnull CSCloud provider) { this.provider = provider; }
    
    public String buildUrl( String command, List params ) throws CloudException, InternalException {
        return buildUrl(command, params.toArray(new Param[params.size()]));
    }

    public String buildUrl(String command, Param ... params) throws CloudException, InternalException {
        ProviderContext ctx = provider.getContext();


        String apiShared = "";
        String apiSecret = "";
        try {
            List fields = provider.getContextRequirements().getConfigurableValues();
            for(ContextRequirements.Field f : fields ) {
                if(f.type.equals(ContextRequirements.FieldType.KEYPAIR)){
                    byte[][] keyPair = (byte[][])ctx.getConfigurationValue(f);
                    apiShared = new String(keyPair[0], "utf-8");
                    apiSecret = new String(keyPair[1], "utf-8");
                }
            }
        }
        catch (UnsupportedEncodingException ignore) {}

        if( ctx == null ) {
            throw new CloudException("No context was set for this request");
        }
        try {
            StringBuilder str = new StringBuilder();
            String apiKey = apiShared;
            String accessKey = apiSecret;

            StringBuilder newKey = new StringBuilder();
            for( int i =0; i 0 ) {
                    port = Integer.parseInt(proxyPort);
                }
                params.setParameter(ConnRoutePNames.DEFAULT_PROXY, new HttpHost(proxyHost, port, ssl ? "https" : "http"));
            }
        }
        return new DefaultHttpClient(params);
    }

    public @Nonnull Document get(@Nonnull String url, @Nonnull String command) throws CloudException, InternalException {
        Logger wire = CSCloud.getLogger(CSMethod.class, "wire");
        Logger logger = CSCloud.getLogger(CSMethod.class, "std");
        
        if( logger.isTraceEnabled() ) {
            logger.trace("enter - " + CSMethod.class.getName() + ".get(" + url + ")");
        }
        if( wire.isDebugEnabled() ) {
            wire.debug("[" + (new Date()) + "] -------------------------------------------------------------------");
            wire.debug("");
        }
        HttpClient client = null;
        try {
            HttpGet get = new HttpGet(url);
            client = getClient(url);
            HttpResponse response;

            get.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
            //get.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
            if( wire.isDebugEnabled() ) {
                wire.debug(get.getRequestLine().toString());
                for( Header header : get.getAllHeaders() ) {
                    wire.debug(header.getName() + ": " + header.getValue());
                }
                wire.debug("");
            }
            try {
                APITrace.trace(provider, command);
                response = client.execute(get);
            }
            catch( IOException e ) {
                logger.error("I/O error from server communications: " + e.getMessage());
                e.printStackTrace();
                throw new InternalException(e);
            }
            int status = response.getStatusLine().getStatusCode();
            if( logger.isDebugEnabled() ) {
                logger.debug("get(): HTTP Status " + status);
            }
            if( wire.isDebugEnabled() ) {
                Header[] headers = response.getAllHeaders();
                
                wire.debug(response.getStatusLine().toString());
                for( Header h : headers ) {
                    if( h.getValue() != null ) {
                        wire.debug(h.getName() + ": " + h.getValue().trim());
                    }
                    else {
                        wire.debug(h.getName() + ":");
                    }
                }
                wire.debug("");                                
            }
            try {
                if( status != HttpServletResponse.SC_OK ) {
                    HttpEntity entity = response.getEntity();
                    String body = (entity == null ? null : EntityUtils.toString(entity));

                    if( body == null ) {
                        CSMethod.ParsedError p = new CSMethod.ParsedError();

                        p.code = status;
                        p.message = "No error information was provided";
                        throw new CSException(CloudErrorType.GENERAL, p);
                    }
                    if( body.contains("") ) {
                        if( status == HttpServletResponse.SC_FORBIDDEN || status == HttpServletResponse.SC_UNAUTHORIZED ) {
                            CSMethod.ParsedError p = new CSMethod.ParsedError();
                            
                            p.code = status;
                            p.message = body;
                            throw new CSException(CloudErrorType.AUTHENTICATION, p);
                        }
                        else if( status == 430 || status == 431 || status == 432 || status == 436 ) {
                            return null;
                        }
                        CSMethod.ParsedError p = new CSMethod.ParsedError();
                        
                        p.code = status;
                        p.message = body;
                        throw new CSException(p);
                    }
                    throw new CSException(parseError(status, body));
                }
                HttpEntity entity = response.getEntity();

                return parseResponse(status, EntityUtils.toString(entity));
            }
            catch( NoHttpResponseException e ) {
                throw new CloudException("No answer from endpoint: " + e.getMessage());
            }
            catch( IOException e ) {
                throw new CloudException("IOException getting stream: " + e.getMessage());
            }
        }
        finally {
            if( wire.isDebugEnabled() ) {
                wire.debug("");
                wire.debug("[" + (new Date()) + "] -------------------------------------------------------------------");
            }
            if( logger.isTraceEnabled() ) {
                logger.trace("exit - " + CSMethod.class.getName() + ".get()");
            }
            if( client != null ) {
                client.getConnectionManager().shutdown();
            }
        }
    }

    private String getSignature(String command, String apiKey, String accessKey, Param ... params) throws UnsupportedEncodingException, SignatureException {
        Logger logger = CSCloud.getLogger(CSMethod.class, "std");
        
        if( logger.isTraceEnabled() ) {
            logger.trace("enter - " + CSMethod.class.getName() + ".getSignature(" + command + "," + apiKey + "," + accessKey + ",[params])");
        }
        try {
            TreeSet sorted = new TreeSet();
            StringBuilder str = new StringBuilder();
            
            sorted.add(new Param("command", URLEncoder.encode(command, "UTF-8").replaceAll("\\+", "%20").toLowerCase()));
            sorted.add(new Param("apikey", URLEncoder.encode(apiKey, "UTF-8").replaceAll("\\+", "%20").toLowerCase()));
            for( Param param : params ) {
                sorted.add(new Param(param.getKey().toLowerCase(), URLEncoder.encode(param.getValue(), "UTF-8").replaceAll("\\+", "%20").toLowerCase()));
            }
            boolean first = true;
            for( Param param : sorted ) {
                if( !first ) {
                    str.append("&");
                }
                first = false;
                str.append(param.getKey());
                str.append("=");
                str.append(param.getValue());
            }
            if( logger.isDebugEnabled()  ) { 
                logger.debug("getSignature(): String to sign=" + str.toString());
            }
            return new String(Base64.encodeBase64(calculateHmac(str.toString(), accessKey)));
        }
        finally {
            if( logger.isTraceEnabled() ) {
                logger.trace("exit - " + CSMethod.class.getName() + ".getSignature()");
            }
        }
    }
    
    private ParsedError parseError(int httpStatus, String assumedXml) throws InternalException {
        Logger logger = CSCloud.getLogger(CSMethod.class, "std");
        
        if( logger.isTraceEnabled() ) {
            logger.trace("enter - " + CSMethod.class.getName() + ".parseError(" + httpStatus + "," + assumedXml + ")");
        }
        try {
            ParsedError error = new ParsedError();
            
            error.code = httpStatus;
            error.message = null;
            try {
                Document doc = parseResponse(httpStatus, assumedXml);
                
                NodeList codes = doc.getElementsByTagName("errorcode");
                for( int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy