/** * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. * * This software is licensed under the GNU General Public License v3 or later. * * It is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or any later version. * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package com.cloud.network; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * @author chiradeep * */ public class HAProxyConfigurator implements LoadBalancerConfigurator { private static String [] globalSection = {"global", "\tlog 127.0.0.1:3914 local0 notice notice", "\tmaxconn 4096", "\tchroot /var/lib/haproxy", "\tuser haproxy", "\tgroup haproxy", "\tdaemon" }; private static String [] defaultsSection = {"defaults", "\tlog global", "\tmode tcp", "\toption dontlognull", "\tretries 3", "\toption redispatch", "\toption forwardfor", "\tstats enable", "\tstats uri /admin?stats", "\tstats realm Haproxy\\ Statistics", "\tstats auth admin1:AdMiN123", "\toption forceclose", "\ttimeout connect 5000", "\ttimeout client 50000", "\ttimeout server 50000" }; private static String [] defaultListen = {"listen vmops 0.0.0.0:9", "\toption transparent" }; @Override public String[] generateConfiguration(List<FirewallRuleVO> fwRules) { //Group the rules by publicip:publicport Map<String, List<FirewallRuleVO>> pools = new HashMap<String, List<FirewallRuleVO>>(); for(FirewallRuleVO rule:fwRules) { StringBuilder sb = new StringBuilder(); String poolName = sb.append(rule.getPublicIpAddress().replace(".", "_")).append('-').append(rule.getPublicPort()).toString(); if (rule.isEnabled() && !rule.isForwarding()) { List<FirewallRuleVO> fwList = pools.get(poolName); if (fwList == null) { fwList = new ArrayList<FirewallRuleVO>(); pools.put(poolName, fwList); } fwList.add(rule); } } List<String> result = new ArrayList<String>(); result.addAll(Arrays.asList(globalSection)); result.add(getBlankLine()); result.addAll(Arrays.asList(defaultsSection)); result.add(getBlankLine()); if (pools.isEmpty()){ //haproxy cannot handle empty listen / frontend or backend, so add a dummy listener //on port 9 result.addAll(Arrays.asList(defaultListen)); } result.add(getBlankLine()); for (Map.Entry<String, List<FirewallRuleVO>> e : pools.entrySet()){ List<String> poolRules = getRulesForPool(e.getKey(), e.getValue()); result.addAll(poolRules); } return result.toArray(new String[result.size()]); } private List<String> getRulesForPool(String poolName, List<FirewallRuleVO> fwRules) { FirewallRuleVO firstRule = fwRules.get(0); String publicIP = firstRule.getPublicIpAddress(); String publicPort = firstRule.getPublicPort(); String algorithm = firstRule.getAlgorithm(); List<String> result = new ArrayList<String>(); //add line like this: "listen 65_37_141_30-80 65.37.141.30:80" StringBuilder sb = new StringBuilder(); sb.append("listen ").append(poolName).append(" ") .append(publicIP).append(":").append(publicPort); result.add(sb.toString()); sb = new StringBuilder(); sb.append("\t").append("balance ").append(algorithm); result.add(sb.toString()); if (publicPort.equals("80")) { sb = new StringBuilder(); sb.append("\t").append("mode http"); result.add(sb.toString()); sb = new StringBuilder(); sb.append("\t").append("option httpclose"); result.add(sb.toString()); } int i=0; for (FirewallRuleVO rule: fwRules) { //add line like this: "server 65_37_141_30-80_3 10.1.1.4:80 check" if (!rule.isEnabled()) continue; sb = new StringBuilder(); sb.append("\t").append("server ").append(poolName) .append("_").append(Integer.toString(i++)).append(" ") .append(rule.getPrivateIpAddress()).append(":").append(rule.getPrivatePort()) .append(" check"); result.add(sb.toString()); } result.add(getBlankLine()); return result; } private String getBlankLine() { return new String("\t "); } public static void main(String [] args) { /* FirewallRulesDao dao = new FirewallRulesDaoImpl(); List<FirewallRuleVO> rules = dao.listIPForwarding(); HAProxyConfigurator hapc = new HAProxyConfigurator(); String [] result = hapc.generateConfiguration(rules); for (int i=0; i < result.length; i++) { System.out.println(result[i]); }*/ } @Override public String[][] generateFwRules(List<FirewallRuleVO> fwRules) { String [][] result = new String [2][]; Set<String> toAdd = new HashSet<String>(); Set<String> toRemove = new HashSet<String>(); for (int i = 0; i < fwRules.size(); i++) { FirewallRuleVO rule = fwRules.get(i); if (rule.isForwarding()) continue; String vlanNetmask = rule.getVlanNetmask(); StringBuilder sb = new StringBuilder(); sb.append(rule.getPublicIpAddress()).append(":"); sb.append(rule.getPublicPort()).append(":"); sb.append(vlanNetmask); String lbRuleEntry = sb.toString(); if (rule.isEnabled()) { toAdd.add(lbRuleEntry); } else { toRemove.add(lbRuleEntry); } } toRemove.removeAll(toAdd); result[ADD] = toAdd.toArray(new String[toAdd.size()]); result[REMOVE] = toRemove.toArray(new String[toRemove.size()]); return result; } }