/**
* This file is part of CloudML [ http://cloudml.org ]
*
* Copyright (C) 2012 - SINTEF ICT
* Contact: Franck Chauvel <franck.chauvel@sintef.no>
*
* Module: root
*
* CloudML is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* CloudML is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with CloudML. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.cloudml.connectors;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.codehaus.jackson.map.ObjectMapper;
/**
* Connector to operate a HAProxy load balancer through the REST API
* pyHrapi @link{https://github.com/igabriel85/modaclouds-loadbalancer-controller}
* which is also developed for MODAClouds
*
* @author Hui Song
* @date 12/02/2015
*/
public class PyHrapiConnector {
private static final String NO_SUCH_GATEWAY = "No such gateway";
private static final String ADDED_GATEWAY = "Added gateway";
private String endpoint = "";
private Version version = null;
private String prefix = "";
private final DefaultHttpClient httpclient = new DefaultHttpClient();
private ObjectMapper mapper = new ObjectMapper();
/**
* Currently only "v1" is supported
*/
public enum Version{
V1("v1");
private final String text;
private Version(final String text) {
this.text = text;
}
public String toString(){
return text;
}
}
public PyHrapiConnector(String endpoint, Version version){
if(!endpoint.startsWith("http://")){
endpoint = "http://"+endpoint;
}
this.endpoint = endpoint;
this.version = version;
this.prefix = String.format("%s/%s", endpoint, version);
}
public void setEndpoint(String endpoint){
this.endpoint = endpoint;
}
private String invoke(URI uri, String method, String body) throws UnsupportedEncodingException, IOException{
HttpUriRequest request = null;
if("GET".equals(method)){
request = new HttpGet(uri);
}
else if("POST".equals(method)){
HttpPost post = new HttpPost(uri);
if(body != null && !body.isEmpty()){
post.setHeader("Content-type", "application/json");
post.setEntity(new StringEntity(body));
}
request = post;
}
else if("PUT".equals(method)){
HttpPut put = new HttpPut(uri);
if(body != null && !body.isEmpty()){
put.setHeader("Content-type", "application/json");
put.setEntity(new StringEntity(body));
}
request = put;
}
else if("DELETE".equals(method)){
request = new HttpDelete(uri);
}
HttpResponse response = httpclient.execute(request);
String s = IOUtils.toString(response.getEntity().getContent());
//TODO: will be removed after debug
System.out.println(s);
return s;
}
private String invoke(String uri, String method, String body) throws UnsupportedEncodingException, IOException, URISyntaxException{
URI request = new URIBuilder(uri).build();
return invoke(request, method, body);
}
private Map invokeToMap(URI uri, String method, String body) throws IOException{
String s = invoke(uri, method, body);
return mapper.readValue(s, Map.class);
}
private Map invokeToMap(String uri, String method, String body) throws IOException, UnsupportedEncodingException, URISyntaxException{
String s = invoke(uri, method, body);
return mapper.readValue(s, Map.class);
}
private List<String> _generalGetToList(String path, String resultLabel){
try{
URI request = new URIBuilder(path).build();
Map result = invokeToMap(request, "GET", null);
return (List<String>)result.get(resultLabel);
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
private Map _generalGet(String path, String errorKey){
try{
URI request = new URIBuilder(path).build();
Map result = invokeToMap(request, "GET", null);
if(result.containsKey(errorKey)){
return null;
}
return result;
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
public String _generalAdd(String path, Map content, String resultKey){
try{
String body = mapper.writeValueAsString(content);
System.out.println(body);
Map result = invokeToMap(path, "PUT", body);
System.out.println(result);
//return (String)result.get(resultKey);
return result.toString();
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
public List<String> getGateways() {
return _generalGetToList(prefix+"/gateways", "Gateways");
}
public Map getGateway(String gateway){
return _generalGet(prefix+"/gateways/"+gateway, NO_SUCH_GATEWAY);
}
public Map getBackEnd(String backend){
return _generalGet(prefix+"/pools/"+backend, "No such pool");
}
public String addGateway(Map gateway){
return _generalAdd(
prefix + "/gateways/"+gateway.get("gateway"),
gateway,
ADDED_GATEWAY
);
}
public String deleteGateway(String gateway){
try{
return invoke(prefix+"/gateways/"+gateway, "DELETE", null);
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
public List<String> getEndpoints(String gateway) {
return _generalGetToList(
String.format("%s/gateways/%s/endpoints", prefix, gateway),
"Endpoints"
);
}
public String getEndpointAddress(String gateway, String endpoint){
try{
URI request = new URIBuilder(String.format("%s/gateways/%s/endpoints/%s",
prefix, gateway, endpoint)).build();
Map result = invokeToMap(request, "GET", null);
return (String) result.get("address");
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
public Object addEndpoint(String gateway, String endpoint, String address) {
try{
Map result = invokeToMap(
String.format("%s/gateways/%s/endpoints/%s", prefix, gateway, endpoint),
"PUT",
"{ \"address\": \""+address+"\" }");
return result;
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
public String deleteEndpoint(String gateway, String endpoint) {
try{
return invoke(
String.format("%s/gateways/%s/endpoints/%s", prefix, gateway, endpoint),
"DELETE",
null);
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
public String start() {
try {
return invoke(prefix+"/controller/commit", "POST", null);
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
public List<String> getPools() {
try{
URI request = new URIBuilder(prefix+"/pools").build();
Map result = invokeToMap(request, "GET", null);
if("No pools present".equals(result.get("Pool Error")))
return Collections.EMPTY_LIST;
return (List<String>)result.get("Pools");
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
public String addPool(String pool, Map<String, Object> content) {
return _generalAdd(
prefix+"/pools/"+pool,
content,
"Added pool"
);
}
public List<String> getTargets(String pool) {
try{
return _generalGetToList(
prefix + "/pools/" + pool + "/targets",
"Targets"
);
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
public String deletePool(String pool){
try{
return invoke(prefix+"/pools/"+pool, "DELETE", null);
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
public Map getPoolTarget(String pool, String target){
return _generalGet(
String.format("%s/pools/%s/targets/%s", prefix, pool, target),
"No such target"
);
}
public String addTarget(String pool, String target, Map content){
return _generalAdd(
String.format("%s/pools/%s/targets/%s", prefix, pool, target),
content,
"x"
);
}
public String deleteTarget(String pool, String target){
try{
return invoke(prefix+"/pools/"+pool+"/targets/"+target, "DELETE", null);
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
public Map getPoolPolicy(String pool){
return _generalGet(
String.format("%s/pools/%s/policy", prefix, pool),
""
);
}
public String setPoolPolicy(String pool, Map content){
return _generalAdd(
String.format("%s/pools/%s/policy", prefix, pool),
content,
""
);
}
public boolean isTargetOnline(String pool, String target){
Map m = _generalGet(
String.format("%s/pools/%s/targets/%s/check", prefix, pool, target),
""
);
return "Online".equals(m.get("Status"));
}
}