diff options
Diffstat (limited to 'config/haproxy')
-rw-r--r-- | config/haproxy/haproxy.inc | 584 | ||||
-rw-r--r-- | config/haproxy/haproxy.xml | 25 | ||||
-rwxr-xr-x | config/haproxy/haproxy_global.php | 92 | ||||
-rwxr-xr-x | config/haproxy/haproxy_listeners.php (renamed from config/haproxy/haproxy_frontends.php) | 79 | ||||
-rwxr-xr-x | config/haproxy/haproxy_listeners_edit.php (renamed from config/haproxy/haproxy_frontends_edit.php) | 544 | ||||
-rwxr-xr-x | config/haproxy/haproxy_pool_edit.php | 494 | ||||
-rwxr-xr-x | config/haproxy/haproxy_pools.php (renamed from config/haproxy/haproxy_servers.php) | 108 | ||||
-rwxr-xr-x | config/haproxy/haproxy_servers_edit.php | 435 |
8 files changed, 1446 insertions, 915 deletions
diff --git a/config/haproxy/haproxy.inc b/config/haproxy/haproxy.inc index dfbec28c..72d9535d 100644 --- a/config/haproxy/haproxy.inc +++ b/config/haproxy/haproxy.inc @@ -34,10 +34,38 @@ require_once("notices.inc"); $d_haproxyconfdirty_path = $g['varrun_path'] . "/haproxy.conf.dirty"; +$a_acltypes = array(); +$a_acltypes[] = array('name' => 'host_starts_with', 'descr' => 'Host starts with', + 'mode' => 'http', 'syntax' => 'hdr_beg(host) -i'); +$a_acltypes[] = array('name' => 'host_ends_with', 'descr' => 'Host ends with', + 'mode' =>'http', 'syntax' => 'hdr_end(host) -i'); +$a_acltypes[] = array('name' => 'host_matches', 'descr' => 'Host matches', + 'mode' =>'http', 'syntax' => 'hdr(host) -i'); +$a_acltypes[] = array('name' => 'host_regex', 'descr' => 'Host regex', + 'mode' =>'http', 'syntax' => 'hdr_reg(host) -i'); +$a_acltypes[] = array('name' => 'host_contains', 'descr' => 'Host contains', + 'mode' => 'http', 'syntax' => 'hdr_dir(host) -i'); +$a_acltypes[] = array('name' => 'path_starts_with', 'descr' => 'Path starts with', + 'mode' => 'http', 'syntax' => 'path_beg -i'); +$a_acltypes[] = array('name' => 'path_ends_with', 'descr' => 'Path ends with', + 'mode' => 'http', 'syntax' => 'path_end -i'); +$a_acltypes[] = array('name' => 'path_matches', 'descr' => 'Path matches', + 'mode' => 'http', 'syntax' => 'path -i'); +$a_acltypes[] = array('name' => 'path_regex', 'descr' => 'Path regex', + 'mode' => 'http', 'syntax' => 'path_reg -i'); +$a_acltypes[] = array('name' => 'path_contains', 'descr' => 'Path contains', + 'mode' => 'http', 'syntax' => 'path_dir -i'); +$a_acltypes[] = array('name' => 'source_ip', 'descr' => 'Source IP', + 'mode' => '', 'syntax' => 'src'); + function haproxy_custom_php_deinstall_command() { exec("rm /usr/local/sbin/haproxy"); exec("rm /usr/local/pkg/haproxy.inc"); exec("rm /usr/local/www/haproxy*"); + exec("rm /usr/local/etc/rc.d/haproxy.sh"); + exec("rm /etc/devd/haproxy.conf"); + exec("/etc/rc.d/devd restart"); + haproxy_install_cron(false); } function haproxy_custom_php_install_command() { @@ -60,6 +88,8 @@ haproxy_enable=\${haproxy-"YES"} start_cmd="haproxy_start" stop_postcmd="haproxy_stop" +check_cmd="haproxy_check" +extra_commands="check" load_rc_config \$name @@ -77,6 +107,20 @@ haproxy_start () { ENDOFF } +haproxy_check () { + echo "Checking haproxy." + /usr/bin/env \ + PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \ + /usr/local/bin/php -q -d auto_prepend_file=config.inc <<ENDOFF + <?php + require_once("globals.inc"); + require_once("functions.inc"); + require_once("haproxy.inc"); + haproxy_check_run(0); + ?> +ENDOFF +} + haproxy_stop () { echo "Stopping haproxy." killall haproxy @@ -91,18 +135,262 @@ EOD; fclose($fd); exec("chmod a+rx /usr/local/etc/rc.d/haproxy.sh"); + $devd = <<<EOD +notify 0 { + match "system" "IFNET"; + match "subsystem" "carp[0-9]+"; + match "type" "LINK_UP"; + action "/usr/local/etc/rc.d/haproxy.sh check"; +}; +notify 0 { + match "system" "IFNET"; + match "subsystem" "carp[0-9]+"; + match "type" "LINK_DOWN"; + action "/usr/local/etc/rc.d/haproxy.sh check"; +}; + +EOD; + exec("mkdir -p /etc/devd"); + $fd = fopen("/etc/devd/haproxy.conf", "w"); + fwrite($fd, $devd); + fclose($fd); + exec("/etc/rc.d/devd restart"); + + /* Do XML upgrade from haproxy 0.31 to haproxy-dev */ + if (is_array($config['installedpackages']['haproxy']['ha_servers'])) { + /* We have an old config */ + $config['installedpackages']['haproxy']['ha_pools']['item'] = array(); + $a_global = &$config['installedpackages']['haproxy']; + $a_backends = &$config['installedpackages']['haproxy']['ha_backends']['item']; + $a_oldservers = &$config['installedpackages']['haproxy']['ha_servers']['item']; + $a_pools = &$config['installedpackages']['haproxy']['ha_pools']['item']; + + foreach ($a_backends as $id => $be) { + $a_backends[$id]['status'] = 'active'; + } + $id = 0; + foreach ($a_oldservers as $oldserver) { + $pool=$oldserver; + /* make server sub array */ + $server=array(); + $server['name'] = $oldserver['name']; + $server['address'] = $oldserver['address']; + $server['port'] = $oldserver['port']; + $server['weight'] = $oldserver['weight']; + $a_servers=array(); + $a_servers[]=$server; + /* set new pool */ + $pool['name'] = "pool$id"; + $id++; + $pool['ha_servers']['item']=$a_servers; + /* link to frontend */ + foreach ($a_backends as $id => $be) { + if ($a_backends[$id]['name'] == $oldserver['backend']) { + $a_backends[$id]['pool'] = $pool['name']; + $pool['monitor_uri'] = $be['monitor_uri']; + unset($a_backends[$id]['monitor_uri']); + break; + } + } + unset($pool['backend']); + unset($pool['address']); + unset($pool['port']); + unset($pool['weight']); + $a_pools[] = $pool; + } + unset($config['installedpackages']['haproxy']['ha_servers']); + write_config(); + } + conf_mount_ro(); exec("/usr/local/etc/rc.d/haproxy.sh start"); } +function haproxy_install_cron($should_install) { + global $config, $g; + if($g['booting']==true) + return; + $is_installed = false; + if(!$config['cron']['item']) + return; + $x=0; + foreach($config['cron']['item'] as $item) { + if(strstr($item['command'], "/usr/local/etc/rc.d/haproxy.sh")) { + $is_installed = true; + break; + } + $x++; + } + switch($should_install) { + case true: + if(!$is_installed) { + $cron_item = array(); + $cron_item['minute'] = "*/2"; + $cron_item['hour'] = "*"; + $cron_item['mday'] = "*"; + $cron_item['month'] = "*"; + $cron_item['wday'] = "*"; + $cron_item['who'] = "root"; + $cron_item['command'] = "/usr/local/etc/rc.d/haproxy.sh check"; + $config['cron']['item'][] = $cron_item; + parse_config(true); + write_config(); + configure_cron(); + } + break; + case false: + if($is_installed == true) { + if($x > 0) { + unset($config['cron']['item'][$x]); + parse_config(true); + write_config(); + } + configure_cron(); + } + break; + } +} + +function haproxy_find_acl($name) { + global $a_acltypes; + + /* XXX why is this broken from xmlsync? */ + if (!$a_acltypes) { + $a_acltypes = array(); + $a_acltypes[] = array('name' => 'host_starts_with', 'descr' => 'Host starts with', + 'mode' => 'http', 'syntax' => 'hdr_beg(host) -i'); + $a_acltypes[] = array('name' => 'host_ends_with', 'descr' => 'Host ends with', + 'mode' =>'http', 'syntax' => 'hdr_end(host) -i'); + $a_acltypes[] = array('name' => 'host_matches', 'descr' => 'Host matches', + 'mode' =>'http', 'syntax' => 'hdr(host) -i'); + $a_acltypes[] = array('name' => 'host_regex', 'descr' => 'Host regex', + 'mode' =>'http', 'syntax' => 'hdr_reg(host) -i'); + $a_acltypes[] = array('name' => 'host_contains', 'descr' => 'Host contains', + 'mode' => 'http', 'syntax' => 'hdr_dir(host) -i'); + $a_acltypes[] = array('name' => 'path_starts_with', 'descr' => 'Path starts with', + 'mode' => 'http', 'syntax' => 'path_beg -i'); + $a_acltypes[] = array('name' => 'path_ends_with', 'descr' => 'Path ends with', + 'mode' => 'http', 'syntax' => 'path_end -i'); + $a_acltypes[] = array('name' => 'path_matches', 'descr' => 'Path matches', + 'mode' => 'http', 'syntax' => 'path -i'); + $a_acltypes[] = array('name' => 'path_regex', 'descr' => 'Path regex', + 'mode' => 'http', 'syntax' => 'path_reg -i'); + $a_acltypes[] = array('name' => 'path_contains', 'descr' => 'Path contains', + 'mode' => 'http', 'syntax' => 'path_dir -i'); + $a_acltypes[] = array('name' => 'source_ip', 'descr' => 'Source IP', + 'mode' => '', 'syntax' => 'src'); + } + + if($a_acltypes) { + foreach ($a_acltypes as $acl) { + if ($acl['name'] == $name) + return $acl; + } + } +} + +function write_backend($fd, $name, $pool, $frontend) { + if(!is_array($pool['ha_servers']['item'])) + return; + + fwrite ($fd, "backend " . $name . "\n"); + if($pool['cookie_name'] && strtolower($frontend['type']) == "http") + fwrite ($fd, "\tcookie\t\t\t" . $pool['cookie_name'] . " insert indirect\n"); + + // https is an alias for tcp for clarity purpouses + if(strtolower($frontend['type']) == "https") { + $backend_type = "tcp"; + $httpchk = "ssl-hello-chk"; + } else { + $backend_type = $frontend['type']; + $httpchk = "httpchk"; + } + + fwrite ($fd, "\tmode\t\t\t" . $backend_type . "\n"); + + if($frontend['balance']) + fwrite ($fd, "\tbalance\t\t\t" . $frontend['balance'] . "\n"); + + if($frontend['connection_timeout']) + fwrite ($fd, "\tcontimeout\t\t" . $frontend['connection_timeout'] . "\n"); + + if($frontend['server_timeout']) + fwrite ($fd, "\tsrvtimeout\t\t" . $frontend['server_timeout'] . "\n"); + + if($frontend['retries']) + fwrite ($fd, "\tretries\t\t\t" . $frontend['retries'] . "\n"); + + if($frontend['stats_enabled']=='yes') { + fwrite ($fd, "\tstats\t\t\tenable\n"); + if($frontend['stats_uri']) + fwrite ($fd, "\tstats\t\t\turi ".$frontend['stats_uri']."\n"); + if($frontend['stats_realm']) + fwrite ($fd, "\tstats\t\t\trealm " . $frontend['stats_realm'] . "\n"); + else + fwrite ($fd, "\tstats\t\t\trealm .\n"); + fwrite ($fd, "\tstats\t\t\tauth " . $frontend['stats_username'].":". $frontend['stats_password']."\n"); + } + + $uri = $pool['monitor_uri']; + if ($pool['monitor_uri']) + $uri = $pool['monitor_uri']; + else + $uri = "/"; + fwrite ($fd, "\toption\t\t\t{$httpchk} HEAD " . $uri . " HTTP/1.0\n"); + + if($pool['cookie'] && strtolower($frontend['type']) == "http") + $cookie = " cookie {$pool['cookie']} "; + else + $cookie = ""; + if($pool['advanced']) { + $advanced = base64_decode($pool['advanced']); + $advanced_txt = " " . $advanced; + } else { + $advanced_txt = ""; + } + if($pool['checkinter']) + $checkinter = "check inter {$pool['checkinter']}"; + else if (strtolower($frontend['type']) != "tcp") + $checkinter = "check inter 1000"; + else + $checkinter = ""; + + $a_servers = &$pool['ha_servers']['item']; + foreach($a_servers as $be) { + if(!$be['port']) { + // the listener can specify a default port + $be['port'] = $frontend['svrport']; + } + if(!$be['port']) { + // last resort, use the frontend port + $ports = split(",", "{$frontend['port']},"); + $be['port'] = $ports[0]; + } + if (!$be['name']) + $be['name'] = $be['address']; + if($be['backup']) { + $isbackup = "backup"; + } else { + $isbackup = ""; + } + fwrite ($fd, "\tserver\t\t\t" . $be['name'] . " " . $be['address'].":" . $be['port'] . " $cookie " . " $checkinter $isbackup weight " . $be['weight'] . "{$advanced_txt}\n"); + } + fwrite ($fd, "\n"); +} + function haproxy_configure() { + // reload haproxy + haproxy_writeconf(); + return haproxy_check_run(1); +} + +function haproxy_writeconf() { global $config, $g; $a_global = &$config['installedpackages']['haproxy']; $a_backends = &$config['installedpackages']['haproxy']['ha_backends']['item']; - $a_frontends = &$config['installedpackages']['haproxy']['ha_frontends']['item']; - $a_servers = &$config['installedpackages']['haproxy']['ha_servers']['item']; + $a_pools = &$config['installedpackages']['haproxy']['ha_pools']['item']; $fd = fopen("{$g['varetc_path']}/haproxy.cfg", "w"); @@ -112,7 +400,7 @@ function haproxy_configure() { fwrite ($fd, "\t" . base64_decode($a_global['advanced']) . "\n"); fwrite ($fd, "\tmaxconn\t\t\t".$a_global['maxconn']."\n"); if($a_global['remotesyslog']) - fwrite ($fd, "\tlog\t\t\t{$a_global['remotesyslog']}\tlocal0\n"); + fwrite ($fd, "\tlog\t\t\t{$a_global['remotesyslog']}\t{$a_global['logfacility']}\t{$a_global['loglevel']}\n"); fwrite ($fd, "\tuid\t\t\t80\n"); fwrite ($fd, "\tgid\t\t\t80\n"); // Set numprocs if defined or use system default (#cores) @@ -126,15 +414,51 @@ function haproxy_configure() { fwrite ($fd, "\n"); } - // Construct and write out configuration file + // Try and get a unique array for address:port as frontends can duplicate + $a_bind = array(); if(is_array($a_backends)) { foreach ($a_backends as $backend) { + if($backend['status'] != 'active') + continue; + if(!$backend['pool']) + continue; + + $bname = $backend['extaddr'] . ":" . $backend['port']; + if (!is_array($a_bind[$bname])) { + $a_bind[$bname] = array(); + $a_bind[$bname]['config'] = array(); + // Settings which are constant for a merged frontend + $a_bind[$bname]['name'] = $backend['name']; + $a_bind[$bname]['extaddr'] = $backend['extaddr']; + $a_bind[$bname]['port'] = $backend['port']; + } + $b = &$a_bind[$bname]; + + // Overwrite ? + $b['type'] = $backend['type']; + $b['forwardfor'] = $backend['forwardfor']; + $b['httpclose'] = $backend['httpclose']; + $b['max_connections'] = $backend['max_connections']; + $b['client_timeout'] = $backend['client_timeout']; + $b['advanced'] = $backend['advanced']; + + // pointer to each backend + $b['config'][] = $backend; + } + } + + $a_pendingpl = array(); - // Define our backend name - $backendinfo = "listen {$backend['name']}\n"; + // Construct and write out configuration file + if(is_array($a_bind)) { + foreach ($a_bind as $bind) { + if (count($bind['config']) > 1) + $frontendinfo = "frontend {$bind['name']}-merged\n"; + else + $frontendinfo = "frontend {$bind['name']}\n"; // Prepare ports for processing by splitting - $portss = "{$backend['port']},"; + $portss = "{$bind['port']},"; $ports = split(",", $portss); // Initialize variable @@ -143,176 +467,184 @@ function haproxy_configure() { // Process and add bind directives for ports foreach($ports as $port) { if($port) { - if($backend['extaddr'] == "any") + if($bind['extaddr'] == "any") $listenip .= "\tbind\t\t\t0.0.0.0:{$port}\n"; - elseif($backend['extaddr']) - $listenip .= "\tbind\t\t\t{$backend['extaddr']}:{$port}\n"; + elseif($bind['extaddr']) + $listenip .= "\tbind\t\t\t{$bind['extaddr']}:{$port}\n"; else $listenip .= "\tbind\t\t\t" . get_current_wan_address('wan') . ":{$port}\n"; } } - fwrite ($fd, "{$backendinfo}"); + fwrite ($fd, "{$frontendinfo}"); fwrite ($fd, "{$listenip}"); // Advanced pass thru - if($backend['advanced']) { - $advanced = base64_decode($backend['advanced']); + if($bind['advanced']) { + $advanced = base64_decode($bind['advanced']); fwrite($fd, "\t" . $advanced . "\n"); } // https is an alias for tcp for clarity purpouses - if(strtolower($backend['type']) == "https") { + if(strtolower($bind['type']) == "https") { $backend_type = "tcp"; $httpchk = "ssl-hello-chk"; } else { - $backend_type = $backend['type']; + $backend_type = $bind['type']; $httpchk = "httpchk"; } - fwrite ($fd, "\tmode\t\t\t" . $backend_type . "\n"); + fwrite ($fd, "\tmode\t\t\t" . $backend_type . "\n"); fwrite ($fd, "\tlog\t\t\tglobal\n"); fwrite ($fd, "\toption\t\t\tdontlognull\n"); - if($backend['httpclose']) + if($bind['httpclose']) fwrite ($fd, "\toption\t\t\thttpclose\n"); - if($backend['forwardfor']) + if($bind['forwardfor']) fwrite ($fd, "\toption\t\t\tforwardfor\n"); - if($backend['max_connections']) - fwrite ($fd, "\tmaxconn\t\t\t" . $backend['max_connections'] . "\n"); - - if($backend['client_timeout']) - fwrite ($fd, "\tclitimeout\t\t" . $backend['client_timeout'] . "\n"); - - if($backend['balance']) - fwrite ($fd, "\tbalance\t\t\t" . $backend['balance'] . "\n"); - - if($backend['connection_timeout']) - fwrite ($fd, "\tcontimeout\t\t" . $backend['connection_timeout'] . "\n"); - - if($backend['server_timeout']) - fwrite ($fd, "\tsrvtimeout\t\t" . $backend['server_timeout'] . "\n"); - - if($backend['retries']) - fwrite ($fd, "\tretries\t\t\t" . $backend['retries'] . "\n"); - - if($backend['cookie_name']) - fwrite ($fd, "\tcookie\t\t\t" . $backend['cookie_name'] . " insert indirect\n"); - - if($backend['monitor_uri']) - fwrite ($fd, "\toption\t\t\t{$httpchk} HEAD " . $backend['monitor_uri'] . " HTTP/1.0\n"); - - if($backend['stats_enabled']=='yes') { - fwrite ($fd, "\tstats\t\t\tenable\n"); - if($backend['stats_uri']) - fwrite ($fd, "\tstats\t\t\turi ".$backend['stats_uri']."\n"); - if($backend['stats_realm']) - fwrite ($fd, "\tstats\t\t\trealm " . $backend['stats_realm'] . "\n"); - else - fwrite ($fd, "\tstats\t\t\trealm .\n"); - fwrite ($fd, "\tstats\t\t\tauth " . $backend['stats_username'].":". $backend['stats_password']."\n"); - if($backend['stats_node_enabled']=='yes') - fwrite ($fd, "\tstats\t\t\tshow-node " . $backend['stats_node'] . "\n"); - if($backend['stats_desc']) - fwrite ($fd, "\tstats\t\t\tshow-desc " . $backend['stats_desc'] . "\n"); - if($backend['stats_refresh']) - fwrite ($fd, "\tstats\t\t\trefresh " . $backend['stats_refresh'] . "\n"); - } + if($bind['max_connections']) + fwrite ($fd, "\tmaxconn\t\t\t" . $bind['max_connections'] . "\n"); - $a_acl=&$frontend['ha_acls']['item']; - if(!is_array($a_acl)) - $a_acl=array(); + if($bind['client_timeout']) + fwrite ($fd, "\tclitimeout\t\t" . $bind['client_timeout'] . "\n"); + + + // Combine the rest of the listener configs + $default_once = 0; + $i = 0; + foreach ($bind['config'] as $bconfig) { + $a_acl=&$bconfig['ha_acls']['item']; + if(!is_array($a_acl)) + $a_acl=array(); - foreach ($a_acl as $acl) - fwrite ($fd, "\tacl\t\t\t".$acl['name']."\t\t".$acl['expression']."\n"); - - $server['backend'] .= " "; - if(is_array($a_servers)) { - foreach ($a_servers as $server) { - $backends_to_process = split(" ", $server['backend']); - foreach($backends_to_process as $backends) { - if($backends == "") - continue; - if($backends == $backend['name']) { - $server_ports = array(); - if($server['status'] != 'inactive') { - if($server['cookie']) - $cookie = " cookie {$server['cookie']} "; - else - $cookie = ""; - if(!$server['port']) { - foreach($ports as $port) { - if($port) - $server_ports[] = $port; - } - } else { - $server_ports[] = $server['port']; - } - if($server['advanced']) { - $advanced = base64_decode($server['advanced']); - $advanced_txt = " " . $advanced; - } else { - $advanced_txt = ""; - } - if($server['status'] != 'active') { - $status = " " . $server['status']; - } else { - $status = ""; - } - if($server['checkinter']) - $checkinter = "check inter {$server['checkinter']}"; - else - $checkinter = "check inter 1000"; - foreach($server_ports as $pport) - fwrite ($fd, "\tserver\t\t\t" . $server['name'] . " " . $server['address'].":" . $pport . " $cookie " . " $checkinter weight " . $server['weight'] . $status . "{$advanced_txt}\n"); - } - } - } + $poolname = $bconfig['pool'] . "_" . strtolower($bconfig['type']); + + // Create different pools if the svrport is set + if ($bconfig['svrport'] > 0) + $poolname .= "_" . $bconfig['svrport']; + + // Write this out once, and must be before any backend config text + if ($default_once == 0) { + fwrite ($fd, "\tdefault_backend\t\t" . $poolname . "\n"); + $default_once++; + } + + if (!isset($a_pendingpl[$poolname])) { + $a_pendingpl[$poolname] = array(); + $a_pendingpl[$poolname]['name'] = $poolname; + $a_pendingpl[$poolname]['frontend'] = $bconfig; + } + + foreach ($a_acl as $entry) { + $acl = haproxy_find_acl($entry['expression']); + if (!$acl) + continue; + + // Filter out acls for different modes + if ($acl['mode'] != '' && $acl['mode'] != strtolower($bind['type'])) + continue; + + if ($acl['syntax'] != '') + $expr = $acl['syntax'] . " " . $entry['value']; + else + $expr = $entry['expression'] . " " . $entry['value']; + + $aclname = $i . "_" . $entry['name']; + fwrite ($fd, "\tacl\t\t\t" . $aclname . "\t" . $expr . "\n"); + fwrite ($fd, "\tuse_backend\t\t" . $poolname . " if " . $aclname . "\n"); + $i++; } + } fwrite ($fd, "\n"); } - // Sync HAProxy configuration (if enabled) - if(isset($config['installedpackages']['haproxy']['enablesync'])) { - if($config['installedpackages']['haproxy']['synchost1']) { - haproxy_do_xmlrpc_sync($config['installedpackages']['haproxy']['synchost1'], - $config['installedpackages']['haproxy']['syncpassword']); - } - if($config['installedpackages']['haproxy']['synchost2']) { - haproxy_do_xmlrpc_sync($config['installedpackages']['haproxy']['synchost2'], - $config['installedpackages']['haproxy']['syncpassword']); - } - if($config['installedpackages']['haproxy']['synchost3']) { - haproxy_do_xmlrpc_sync($config['installedpackages']['haproxy']['synchost3'], - $config['installedpackages']['haproxy']['syncpassword']); + } + if (is_array($a_pendingpl) && is_array($a_pools)) { + foreach ($a_pendingpl as $pending) { + foreach ($a_pools as $pool) { + if ($pending['frontend']['pool'] == $pool['name']) { + write_backend($fd, $pending['name'], $pool, $pending['frontend']); + } } } } + fwrite ($fd, "\n"); + + // Sync HAProxy configuration (if enabled) + if(isset($config['installedpackages']['haproxy']['enablesync'])) { + if($config['installedpackages']['haproxy']['synchost1']) { + haproxy_do_xmlrpc_sync($config['installedpackages']['haproxy']['synchost1'], + $config['installedpackages']['haproxy']['syncpassword']); + } + if($config['installedpackages']['haproxy']['synchost2']) { + haproxy_do_xmlrpc_sync($config['installedpackages']['haproxy']['synchost2'], + $config['installedpackages']['haproxy']['syncpassword']); + } + if($config['installedpackages']['haproxy']['synchost3']) { + haproxy_do_xmlrpc_sync($config['installedpackages']['haproxy']['synchost3'], + $config['installedpackages']['haproxy']['syncpassword']); + } + } // create config file fclose($fd); + if (isset($a_global['carpdev'])) + haproxy_install_cron(true); + else + haproxy_install_cron(false); + $freebsd_version = substr(trim(`uname -r`), 0, 1); if(!file_exists("/usr/bin/limits")) { exec("fetch -q -o /usr/bin/limits http://files.pfsense.org/extras/{$freebsd_version}/limits"); exec("chmod a+rx /usr/bin/limits"); } +} + +function haproxy_is_running() { + $running = (shell_exec("/bin/pgrep -x haproxy") != ''); + return $running; +} + +function haproxy_check_run($reload) { + global $config, $g; + + $a_global = &$config['installedpackages']['haproxy']; exec("/usr/bin/limits -n 300014"); - // reload haproxy if(isset($a_global['enable'])) { - if(is_process_running('haproxy')) { + if (isset($a_global['carpdev'])) { + $status = get_carp_interface_status($a_global['carpdev']); + if ($status != "MASTER") { + if (haproxy_is_running()) { + log_error("Stopping haproxy on CARP backup."); + exec("/bin/pkill -F /var/run/haproxy.pid haproxy"); + } + return (0); + } else if (haproxy_is_running() && $reload == 0) { + return (0); + } + log_error("Starting haproxy on CARP master."); + /* fallthrough */ + } else if ($reload == 0) + return (0); + + if (haproxy_is_running()) { exec("/usr/local/sbin/haproxy -f /var/etc/haproxy.cfg -p /var/run/haproxy.pid -st `cat /var/run/haproxy.pid`"); } else { exec("/usr/local/sbin/haproxy -f /var/etc/haproxy.cfg -p /var/run/haproxy.pid -D"); } return (0); } else { + if ($reload && haproxy_is_running()) { + exec("/bin/pkill -F /var/run/haproxy.pid haproxy"); + } return (1); } + } function haproxy_do_xmlrpc_sync($sync_to_ip, $password) { @@ -362,11 +694,11 @@ function haproxy_do_xmlrpc_sync($sync_to_ip, $password) { $xml['haproxy'] = $config['installedpackages']['haproxy']; // Prevent sync loops - unset($xml['haproxy']['synchost1']); - unset($xml['haproxy']['synchost2']); - unset($xml['haproxy']['synchost3']); - unset($xml['haproxy']['syncpassword']); - + unset($xml['synchost1']); + unset($xml['synchost2']); + unset($xml['synchost3']); + unset($xml['syncpassword']); + /* assemble xmlrpc payload */ $params = array( XML_RPC_encode($password), diff --git a/config/haproxy/haproxy.xml b/config/haproxy/haproxy.xml index bc338764..83e2ca5d 100644 --- a/config/haproxy/haproxy.xml +++ b/config/haproxy/haproxy.xml @@ -44,13 +44,13 @@ <name>haproxy</name> <version>1.0</version> <title>HAProxy</title> - <aftersaveredirect>/pkg_edit.php?xml=haproxy_servers.php</aftersaveredirect> + <aftersaveredirect>/pkg_edit.php?xml=haproxy_pools.php</aftersaveredirect> <include_file>/usr/local/pkg/haproxy.inc</include_file> <menu> <name>HAProxy</name> <tooltiptext></tooltiptext> <section>Services</section> - <url>/haproxy_global.php</url> + <url>/haproxy_listeners.php</url> </menu> <service> <name>HAProxy</name> @@ -62,32 +62,32 @@ <additional_files_needed> <prefix>/usr/local/pkg/</prefix> <chmod>077</chmod> - <item>http://www.pfsense.com/packages/config/haproxy/haproxy.inc</item> + <item>http://www.pfsense.com/packages/config/haproxy-dev/haproxy.inc</item> </additional_files_needed> <additional_files_needed> <prefix>/usr/local/www/</prefix> <chmod>077</chmod> - <item>http://www.pfsense.com/packages/config/haproxy/haproxy_frontends.php</item> + <item>http://www.pfsense.com/packages/config/haproxy-dev/haproxy_listeners.php</item> </additional_files_needed> <additional_files_needed> <prefix>/usr/local/www/</prefix> <chmod>077</chmod> - <item>http://www.pfsense.com/packages/config/haproxy/haproxy_frontends_edit.php</item> + <item>http://www.pfsense.com/packages/config/haproxy-dev/haproxy_listeners_edit.php</item> </additional_files_needed> <additional_files_needed> <prefix>/usr/local/www/</prefix> <chmod>077</chmod> - <item>http://www.pfsense.com/packages/config/haproxy/haproxy_global.php</item> + <item>http://www.pfsense.com/packages/config/haproxy-dev/haproxy_global.php</item> </additional_files_needed> <additional_files_needed> <prefix>/usr/local/www/</prefix> <chmod>077</chmod> - <item>http://www.pfsense.com/packages/config/haproxy/haproxy_servers.php</item> + <item>http://www.pfsense.com/packages/config/haproxy-dev/haproxy_pools.php</item> </additional_files_needed> <additional_files_needed> <prefix>/usr/local/www/</prefix> <chmod>077</chmod> - <item>http://www.pfsense.com/packages/config/haproxy/haproxy_servers_edit.php</item> + <item>http://www.pfsense.com/packages/config/haproxy-dev/haproxy_pool_edit.php</item> </additional_files_needed> <custom_delete_php_command> </custom_delete_php_command> @@ -96,18 +96,15 @@ <custom_php_resync_config_command> </custom_php_resync_config_command> <custom_php_install_command> - /* - included in package install $freebsdv=trim(`uname -r | cut -d'.' -f1`); conf_mount_rw(); - `fetch -q -o /usr/local/sbin/ http://www.pfsense.org/packages/config/haproxy/binaries{$freebsdv}/haproxy`; + `fetch -q -o /usr/local/sbin/ http://www.pfsense.org/packages/config/haproxy-dev/binaries{$freebsdv}/haproxy`; exec("chmod a+rx /usr/local/sbin/haproxy"); - */ haproxy_custom_php_install_command(); </custom_php_install_command> <custom_php_deinstall_command> haproxy_custom_php_deinstall_command(); </custom_php_deinstall_command> - <custom_php_command_before_form> + <custom_php_command_before_form> </custom_php_command_before_form> -</packagegui>
\ No newline at end of file +</packagegui> diff --git a/config/haproxy/haproxy_global.php b/config/haproxy/haproxy_global.php index b0486fb8..1ef28005 100755 --- a/config/haproxy/haproxy_global.php +++ b/config/haproxy/haproxy_global.php @@ -56,6 +56,9 @@ if ($_POST) { $reqdfieldsn = explode(",", "Maximum connections"); } + if ($_POST['carpdev'] == "disabled") + unset($_POST['carpdev']); + do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors); if ($_POST['maxconn'] && (!is_numeric($_POST['maxconn']))) @@ -74,10 +77,13 @@ if ($_POST) { $config['installedpackages']['haproxy']['enablesync'] = $_POST['enablesync'] ? true : false; $config['installedpackages']['haproxy']['synchost1'] = $_POST['synchost1'] ? $_POST['synchost1'] : false; $config['installedpackages']['haproxy']['synchost2'] = $_POST['synchost2'] ? $_POST['synchost2'] : false; - $config['installedpackages']['haproxy']['synchost3'] = $_POST['synchost3'] ? $_POST['synchost3'] : false; + $config['installedpackages']['haproxy']['synchost2'] = $_POST['synchost3'] ? $_POST['synchost3'] : false; $config['installedpackages']['haproxy']['remotesyslog'] = $_POST['remotesyslog'] ? $_POST['remotesyslog'] : false; + $config['installedpackages']['haproxy']['logfacility'] = $_POST['logfacility'] ? $_POST['logfacility'] : false; + $config['installedpackages']['haproxy']['loglevel'] = $_POST['loglevel'] ? $_POST['loglevel'] : false; + $config['installedpackages']['haproxy']['carpdev'] = $_POST['carpdev'] ? $_POST['carpdev'] : false; $config['installedpackages']['haproxy']['syncpassword'] = $_POST['syncpassword'] ? $_POST['syncpassword'] : false; - $config['installedpackages']['haproxy']['advanced'] = $_POST['advanced'] ? base64_encode($_POST['advanced']) : false; + $config['installedpackages']['haproxy']['advanced'] = base64_encode($_POST['advanced']) ? $_POST['advanced'] : false; $config['installedpackages']['haproxy']['nbproc'] = $_POST['nbproc'] ? $_POST['nbproc'] : false; touch($d_haproxyconfdirty_path); write_config(); @@ -94,9 +100,18 @@ $pconfig['synchost1'] = $config['installedpackages']['haproxy']['synchost1']; $pconfig['synchost2'] = $config['installedpackages']['haproxy']['synchost2']; $pconfig['synchost3'] = $config['installedpackages']['haproxy']['synchost3']; $pconfig['remotesyslog'] = $config['installedpackages']['haproxy']['remotesyslog']; +$pconfig['logfacility'] = $config['installedpackages']['haproxy']['logfacility']; +$pconfig['loglevel'] = $config['installedpackages']['haproxy']['loglevel']; +$pconfig['carpdev'] = $config['installedpackages']['haproxy']['carpdev']; $pconfig['advanced'] = base64_decode($config['installedpackages']['haproxy']['advanced']); $pconfig['nbproc'] = $config['installedpackages']['haproxy']['nbproc']; +// defaults +if (!$pconfig['logfacility']) + $pconfig['logfacility'] = 'local0'; +if (!$pconfig['loglevel']) + $pconfig['loglevel'] = 'info'; + $pfSversion = str_replace("\n", "", file_get_contents("/etc/version")); if(strstr($pfSversion, "1.2")) $one_two = true; @@ -133,8 +148,8 @@ function enable_change(enable_change) { /* active tabs */ $tab_array = array(); $tab_array[] = array("Settings", true, "haproxy_global.php"); - $tab_array[] = array("Frontends", false, "haproxy_frontends.php"); - $tab_array[] = array("Servers", false, "haproxy_servers.php"); + $tab_array[] = array("Listener", false, "haproxy_listeners.php"); + $tab_array[] = array("Server Pool", false, "haproxy_pools.php"); display_top_tabs($tab_array); ?> </td></tr> @@ -221,6 +236,75 @@ function enable_change(enable_change) { </td> </tr> <tr> + <td valign="top" class="vncell"> + Syslog facility + </td> + <td class="vtable"> + <select name="logfacility" class="formfld"> + <?php + $facilities = array("kern", "user", "mail", "daemon", "auth", "syslog", "lpr", + "news", "uucp", "cron", "auth2", "ftp", "ntp", "audit", "alert", "cron2", + "local0", "local1", "local2", "local3", "local4", "local5", "local6", "local7"); + foreach ($facilities as $f): + ?> + <option value="<?=$f;?>" <?php if ($f == $pconfig['logfacility']) echo "selected"; ?>> + <?=$f;?> + </option> + <?php + endforeach; + ?> + </select> + </td> + </tr> + <tr> + <td valign="top" class="vncell"> + Syslog level + </td> + <td class="vtable"> + <select name="loglevel" class="formfld"> + <?php + $levels = array("emerg", "alert", "crit", "err", "warning", "notice", "info", "debug"); + foreach ($levels as $l): + ?> + <option value="<?=$l;?>" <?php if ($l == $pconfig['loglevel']) echo "selected"; ?>> + <?=$l;?> + </option> + <?php + endforeach; + ?> + </select> + </td> + </tr> + <tr> + <td valign="top" class="vncell"> + Carp monitor + </td> + <td class="vtable"> + <select name="carpdev" class="formfld"> + <option value="disabled" <?php if (!isset($pconfig['carpdev'])) echo "selected"; ?>> + disabled + </option> + <?php + if(is_array($config['virtualip']['vip'])) { + foreach($config['virtualip']['vip'] as $carp): + if ($carp['mode'] != "carp") continue; + $ipaddress = $carp['subnet']; + $carp_int = find_carp_interface($ipaddress); + ?> + <option value="<?=$carp_int;?>" + <?php if (isset($pconfig['carpdev']) && $carp_int == $pconfig['carpdev']) echo "selected"; ?>> + <?=$carp_int;?> (<?=$ipaddress;?>) + </option> + <?php + endforeach; + } + ?> + </select> + <br/> + Monitor carp interface and only run haproxy on the firewall which is MASTER. + </td> + </tr> + <tr> <td> </td> diff --git a/config/haproxy/haproxy_frontends.php b/config/haproxy/haproxy_listeners.php index d50133b8..ef67108b 100755 --- a/config/haproxy/haproxy_frontends.php +++ b/config/haproxy/haproxy_listeners.php @@ -54,14 +54,14 @@ if ($_POST) { } if ($_GET['act'] == "del") { - if ($a_backend[$_GET['id']]) { + if (isset($a_backend[$_GET['id']])) { if (!$input_errors) { unset($a_backend[$_GET['id']]); write_config(); touch($d_haproxyconfdirty_path); - header("Location: haproxy_frontends.php"); - exit; } + header("Location: haproxy_listeners.php"); + exit; } } @@ -69,13 +69,13 @@ $pfSversion = str_replace("\n", "", file_get_contents("/etc/version")); if(strstr($pfSversion, "1.2")) $one_two = true; -$pgtitle = "Services: HAProxy: Frontend"; +$pgtitle = "Services: HAProxy: Listener"; include("head.inc"); ?> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <?php include("fbegin.inc"); ?> -<form action="haproxy_frontends.php" method="post"> +<form action="haproxy_listeners.php" method="post"> <?php if($one_two): ?> <p class="pgtitle"><?=$pgtitle?></p> <?php endif; ?> @@ -89,10 +89,10 @@ include("head.inc"); <?php /* active tabs */ $tab_array = array(); - $tab_array[] = array("Settings", false, "haproxy_global.php"); - $tab_array[] = array("Frontends", true, "haproxy_frontends.php"); - $tab_array[] = array("Servers", false, "haproxy_servers.php"); - display_top_tabs($tab_array); + $tab_array[] = array("Settings", false, "haproxy_global.php"); + $tab_array[] = array("Listener", true, "haproxy_listeners.php"); + $tab_array[] = array("Server Pool", false, "haproxy_pools.php"); + display_top_tabs($tab_array); ?> </td></tr> <tr> @@ -100,42 +100,65 @@ include("head.inc"); <div id="mainarea"> <table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0"> <tr> - <td width="30%" class="listhdrr">Name</td> - <td width="40%" class="listhdrr">Description</td> - <td width="10%" class="listhdrr">Stats URI</td> + <td width="20%" class="listhdrr">Name</td> + <td width="30%" class="listhdrr">Description</td> + <td width="20%" class="listhdrr">Address</td> <td width="10%" class="listhdrr">Type</td> - <td width="10%" class="list"></td> - </tr> - <?php $i = 0; foreach ($a_backend as $backend): ?> + <td width="10%" class="listhdrr">Server pool</td> + <td width="5%" class="list"></td> + </tr> +<?php + $i = 0; + foreach ($a_backend as $backend): + $textss = $textse = ""; + if ($backend['status'] != 'active') { + $textss = "<span class=\"gray\">"; + $textse = "</span>"; + } +?> <tr> - <td class="listlr" ondblclick="document.location='haproxy_frontends_edit.php?id=<?=$i;?>';"> - <?=$backend['name'];?> + <td class="listlr" ondblclick="document.location='haproxy_listeners_edit.php?id=<?=$i;?>';"> + <?=$textss . $backend['name'] . $textse;?> + </td> + <td class="listlr" ondblclick="document.location='haproxy_listeners_edit.php?id=<?=$i;?>';"> + <?=$textss . $backend['desc'] . $textse;?> + </td> + <td class="listlr" ondblclick="document.location='haproxy_listeners_edit.php?id=<?=$i;?>';"> +<?php + echo $textss; + if($backend['extaddr'] == "any") + echo "0.0.0.0"; + elseif($backend['extaddr']) + echo $backend['extaddr']; + else + echo get_current_wan_address('wan'); + echo ":" . $backend['port']; + echo $textse; +?> </td> - <td class="listlr" ondblclick="document.location='haproxy_frontends_edit.php?id=<?=$i;?>';"> - <?=$backend['desc'];?> + <td class="listlr" ondblclick="document.location='haproxy_listeners_edit.php?id=<?=$i;?>';"> + <?=$textss . $backend['type'] . $textse;?> </td> - <td class="listlr" ondblclick="document.location='haproxy_frontends_edit.php?id=<?=$i;?>';"> - <?=$backend['stats_uri'];?> - </td> - <td class="listlr" ondblclick="document.location='haproxy_frontends_edit.php?id=<?=$i;?>';"> - <?=$backend['type'];?> + <td class="listlr" ondblclick="document.location='haproxy_listeners_edit.php?id=<?=$i;?>';"> + <?=$textss . $backend['pool'] . $textse;?> </td> <td class="list" nowrap> <table border="0" cellspacing="0" cellpadding="1"> <tr> - <td valign="middle"><a href="haproxy_frontends_edit.php?id=<?=$i;?>"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" width="17" height="17" border="0"></a></td> - <td valign="middle"><a href="haproxy_frontends.php?act=del&id=<?=$i;?>" onclick="return confirm('Do you really want to delete this entry?')"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0"></a></td> + <td valign="middle"><a href="haproxy_listeners_edit.php?id=<?=$i;?>"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" width="17" height="17" border="0"></a></td> + <td valign="middle"><a href="haproxy_listeners.php?act=del&id=<?=$i;?>" onclick="return confirm('Do you really want to delete this entry?')"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0"></a></td> + <td valign="middle"><a href="haproxy_listeners_edit.php?dup=<?=$i;?>"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0"></a></td> </tr> </table> </td> </tr> <?php $i++; endforeach; ?> <tr> - <td class="list" colspan="4"></td> + <td class="list" colspan="5"></td> <td class="list"> <table border="0" cellspacing="0" cellpadding="1"> <tr> - <td valign="middle"><a href="haproxy_frontends_edit.php"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0"></a></td> + <td valign="middle"><a href="haproxy_listeners_edit.php"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0"></a></td> </tr> </table> </td> diff --git a/config/haproxy/haproxy_frontends_edit.php b/config/haproxy/haproxy_listeners_edit.php index df2411b2..22be121b 100755 --- a/config/haproxy/haproxy_frontends_edit.php +++ b/config/haproxy/haproxy_listeners_edit.php @@ -1,7 +1,7 @@ <?php /* $Id: load_balancer_pool_edit.php,v 1.24.2.23 2007/03/03 00:07:09 smos Exp $ */ /* - haproxy_frontends_edit.php + haproxy_listeners_edit.php part of pfSense (http://www.pfsense.com/) Copyright (C) 2009 Scott Ullrich <sullrich@pfsense.com> Copyright (C) 2008 Remco Hoef <remcoverhoef@pfsense.com> @@ -30,6 +30,18 @@ */ require("guiconfig.inc"); +require_once("haproxy.inc"); + +function haproxy_acl_select($mode) { + global $a_acltypes; + + $seltext = ''; + foreach ($a_acltypes as $expr) { + if ($expr['mode'] == '' || $expr['mode'] == $mode) + $seltext .= "<option value='" . $expr['name'] . "'>" . $expr['descr'] .":</option>"; + } + return $seltext; +} $d_haproxyconfdirty_path = $g['varrun_path'] . "/haproxy.conf.dirty"; @@ -38,22 +50,27 @@ if (!is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) { } $a_backend = &$config['installedpackages']['haproxy']['ha_backends']['item']; +$a_pools = &$config['installedpackages']['haproxy']['ha_pools']['item']; + if (isset($_POST['id'])) $id = $_POST['id']; else $id = $_GET['id']; +if (isset($_GET['dup'])) + $id = $_GET['dup']; + if (isset($id) && $a_backend[$id]) { $pconfig['name'] = $a_backend[$id]['name']; $pconfig['desc'] = $a_backend[$id]['desc']; + $pconfig['status'] = $a_backend[$id]['status']; $pconfig['connection_timeout'] = $a_backend[$id]['connection_timeout']; $pconfig['server_timeout'] = $a_backend[$id]['server_timeout']; $pconfig['retries'] = $a_backend[$id]['retries']; $pconfig['type'] = $a_backend[$id]['type']; $pconfig['balance'] = $a_backend[$id]['balance']; - $pconfig['monitor_uri'] = $a_backend[$id]['monitor_uri']; $pconfig['forwardfor'] = $a_backend[$id]['forwardfor']; $pconfig['httpclose'] = $a_backend[$id]['httpclose']; @@ -63,22 +80,23 @@ if (isset($id) && $a_backend[$id]) { $pconfig['stats_password'] = $a_backend[$id]['stats_password']; $pconfig['stats_uri'] = $a_backend[$id]['stats_uri']; $pconfig['stats_realm'] = $a_backend[$id]['stats_realm']; - $pconfig['stats_node_enabled'] = $a_backend[$id]['stats_node_enabled']; - $pconfig['stats_node'] = $a_backend[$id]['stats_node']; - $pconfig['stats_desc'] = $a_backend[$id]['stats_desc']; - $pconfig['stats_refresh'] = $a_backend[$id]['stats_refresh']; - + $pconfig['type'] = $a_backend[$id]['type']; $pconfig['extaddr'] = $a_backend[$id]['extaddr']; + $pconfig['pool'] = $a_backend[$id]['pool']; $pconfig['max_connections'] = $a_backend[$id]['max_connections']; $pconfig['client_timeout'] = $a_backend[$id]['client_timeout']; $pconfig['port'] = $a_backend[$id]['port']; + $pconfig['svrport'] = $a_backend[$id]['svrport']; $pconfig['a_acl']=&$a_backend[$id]['ha_acls']['item']; $pconfig['advanced'] = base64_decode($a_backend[$id]['advanced']); } -$changedesc = "Services: HAProxy: Frontend"; +if (isset($_GET['dup'])) + unset($id); + +$changedesc = "Services: HAProxy: Listener"; $changecount = 0; if ($_POST) { @@ -134,13 +152,14 @@ if ($_POST) { /* Ensure that our pool names are unique */ for ($i=0; isset($config['installedpackages']['haproxy']['ha_backends']['item'][$i]); $i++) if (($_POST['name'] == $config['installedpackages']['haproxy']['ha_backends']['item'][$i]['name']) && ($i != $id)) - $input_errors[] = "This backend name has already been used. Frontend names must be unique."; + $input_errors[] = "This listener name has already been used. Listener names must be unique."; $a_acl=array(); $acl_names=array(); for($x=0; $x<99; $x++) { $acl_name=$_POST['acl_name'.$x]; $acl_expression=$_POST['acl_expression'.$x]; + $acl_value=$_POST['acl_value'.$x]; if ($acl_name) { // check for duplicates @@ -153,13 +172,14 @@ if ($_POST) { $acl=array(); $acl['name']=$acl_name; $acl['expression']=$acl_expression; + $acl['value']=$acl_value; $a_acl[]=$acl; if (preg_match("/[^a-zA-Z0-9\.\-_]/", $acl_name)) $input_errors[] = "The field 'Name' contains invalid characters."; - if (!preg_match("/.{2,}/", $acl_expression)) - $input_errors[] = "The field 'Expression' is required."; + if (!preg_match("/.{2,}/", $acl_value)) + $input_errors[] = "The field 'Value' is required."; if (!preg_match("/.{2,}/", $acl_name)) $input_errors[] = "The field 'Name' is required."; @@ -177,53 +197,16 @@ if ($_POST) { if($backend['name'] != "") $changedesc .= " modified '{$backend['name']}' pool:"; - if ($backend['name']!=$_POST['name']) { - // name changed: - // * update servers - // * update frontend (default backend and acl) - if (!is_array($config['installedpackages']['haproxy']['ha_servers']['item'])) { - $config['installedpackages']['haproxy']['ha_servers']['item'] = array(); - } - $a_server = &$config['installedpackages']['haproxy']['ha_servers']['item']; - - for ( $i = 0; $i < count($a_server); $i++) { - if ($a_server[$i]['backend']==$backend['name']) { - $a_server[$i]['backend']=$_POST['name']; - } - } - - if (!is_array($config['installedpackages']['haproxy']['ha_frontends']['item'])) { - $config['installedpackages']['haproxy']['ha_frontends']['item'] = array(); - } - $a_frontend = &$config['installedpackages']['haproxy']['ha_frontends']['item']; - - for ( $i = 0; $i < count($a_frontend); $i++) { - if ($a_frontend[$i]['backend']==$backend['name']) { - $a_frontend[$i]['backend']=$_POST['name']; - } - - if (!is_array($a_frontend[$i]['ha_acls']['item'])) { - $a_frontend[$i]['ha_acls']['item'] = array(); - } - - $a_acl = &$a_frontend[$i]['ha_acls']['item']; - for ( $j = 0; $j < count($a_acl); $j++) { - if ($a_acl[$j]['backend']==$backend['name']) { - $a_acl[$j]['backend']=$_POST['name']; - } - } - } - } update_if_changed("name", $backend['name'], $_POST['name']); update_if_changed("description", $backend['desc'], $_POST['desc']); + update_if_changed("status", $backend['status'], $_POST['status']); update_if_changed("connection_timeout", $backend['connection_timeout'], $_POST['connection_timeout']); update_if_changed("server_timeout", $backend['server_timeout'], $_POST['server_timeout']); update_if_changed("retries", $backend['retries'], $_POST['retries']); update_if_changed("type", $backend['type'], $_POST['type']); update_if_changed("balance", $backend['balance'], $_POST['balance']); update_if_changed("cookie_name", $backend['cookie_name'], $_POST['cookie_name']); - update_if_changed("monitor_uri", $backend['monitor_uri'], $_POST['monitor_uri']); update_if_changed("forwardfor", $backend['forwardfor'], $_POST['forwardfor']); update_if_changed("httpclose", $backend['httpclose'], $_POST['httpclose']); update_if_changed("stats_enabled", $backend['stats_enabled'], $_POST['stats_enabled']); @@ -231,13 +214,11 @@ if ($_POST) { update_if_changed("stats_password", $backend['stats_password'], $_POST['stats_password']); update_if_changed("stats_uri", $backend['stats_uri'], $_POST['stats_uri']); update_if_changed("stats_realm", $backend['stats_realm'], $_POST['stats_realm']); - update_if_changed("stats_node_enabled", $backend['stats_node_enabled'], $_POST['stats_node_enabled']); - update_if_changed("stats_node", $backend['stats_node'], $_POST['stats_node']); - update_if_changed("stats_desc", $backend['stats_desc'], $_POST['stats_desc']); - update_if_changed("stats_desc", $backend['stats_refresh'], $_POST['stats_refresh']); update_if_changed("type", $backend['type'], $_POST['type']); update_if_changed("port", $backend['port'], $_POST['port']); + update_if_changed("svrport", $backend['svrport'], $_POST['svrport']); update_if_changed("extaddr", $backend['extaddr'], $_POST['extaddr']); + update_if_changed("pool", $backend['pool'], $_POST['pool']); update_if_changed("max_connections", $backend['max_connections'], $_POST['max_connections']); update_if_changed("client_timeout", $backend['client_timeout'], $_POST['client_timeout']); update_if_changed("advanced", $backend['advanced'], base64_encode($_POST['advanced'])); @@ -255,7 +236,7 @@ if ($_POST) { write_config($changedesc); } - header("Location: haproxy_frontends.php"); + header("Location: haproxy_listeners.php"); exit; } } @@ -264,12 +245,16 @@ $pfSversion = str_replace("\n", "", file_get_contents("/etc/version")); if(strstr($pfSversion, "1.2")) $one_two = true; -$pgtitle = "HAProxy: Frontend: Edit"; +$pgtitle = "HAProxy: Listener: Edit"; include("head.inc"); ?> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> +<?php if($one_two): ?> +<script type="text/javascript" src="/javascript/scriptaculous/prototype.js"></script> +<script type="text/javascript" src="/javascript/scriptaculous/scriptaculous.js"></script> +<?php endif; ?> <script type="text/javascript"> // Global Variables var rowname = new Array(99); @@ -291,33 +276,93 @@ include("head.inc"); var addRowTo = (function() { return (function (tableId) { - var d, tbody, tr, td, bgc, i, ii, j; + var d, tbody, tr, td, bgc, i, ii, j, type, seltext; + var btable, btbody, btr, btd; + d = document; + type = d.getElementById("type").value; + if (type == 'health') + seltext = "<?php echo haproxy_acl_select('health');?>"; + else if (type == 'tcp') + seltext = "<?php echo haproxy_acl_select('tcp');?>"; + else if (type == 'https') + seltext = "<?php echo haproxy_acl_select('https');?>"; + else + seltext = "<?php echo haproxy_acl_select('http');?>"; + if (seltext == '') { + alert("No ACL types available in current listener mode"); + return; + } + tbody = d.getElementById(tableId).getElementsByTagName("tbody").item(0); tr = d.createElement("tr"); totalrows++; + tr.setAttribute("id","aclrow" + totalrows); for (i = 0; i < field_counter_js; i++) { td = d.createElement("td"); if(rowtype[i] == 'textbox') { - td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + "'></input><input size='" + rowsize[i] + "' name='" + rowname[i] + totalrows + "'></input> "; + td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + + "'></input><input size='" + rowsize[i] + "' name='" + rowname[i] + totalrows + + "' id='" + rowname[i] + totalrows + + "'></input> "; } else if(rowtype[i] == 'select') { - td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + "'></input><select name='" + rowname[i] + totalrows + "'><?php foreach ($a_backend as $backend) {?><option value=\"<?=$backend['name']?>\"><?=$backend['name']?></option><?php }?></select> "; + td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + + "'></input><select name='" + rowname[i] + totalrows + + "' id='" + rowname[i] + totalrows + + "'>" + seltext + "</select> "; } else { - td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + "'></input><input type='checkbox' name='" + rowname[i] + totalrows + "'></input> "; + td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + + "'></input><input type='checkbox' name='" + rowname[i] + totalrows + + "' id='" + rowname[i] + totalrows + "'></input> "; } tr.appendChild(td); } - td = d.createElement("td"); - td.rowSpan = "1"; - td.className = "list"; - td.innerHTML = '<img src="/themes/' + theme + '/images/icons/icon_x.gif" width="17" height="17" border="0" onclick="removeRow(this); return false;">'; + td = d.createElement("td"); + td.rowSpan = "1"; + td.setAttribute("class","list"); + + // Recreate the button table. + btable = document.createElement("table"); + btable.setAttribute("border", "0"); + btable.setAttribute("cellspacing", "0"); + btable.setAttribute("cellpadding", "1"); + btbody = document.createElement("tbody"); + btr = document.createElement("tr"); + btd = document.createElement("td"); + btd.setAttribute("valign", "middle"); + btd.innerHTML = '<img src="/themes/' + theme + '/images/icons/icon_x.gif" title="delete entry" width="17" height="17" border="0" onclick="removeRow(this); return false;">'; + btr.appendChild(btd); + btd = document.createElement("td"); + btd.setAttribute("valign", "middle"); + btd.innerHTML = '<img src="/themes/' + theme + "/images/icons/icon_plus.gif\" title=\"duplicate entry\" width=\"17\" height=\"17\" border=\"0\" onclick=\"dupRow(" + totalrows + ", 'acltable'); return false;\">"; + btr.appendChild(btd); + btbody.appendChild(btr); + btable.appendChild(btbody); + + td.appendChild(btable); tr.appendChild(td); tbody.appendChild(tr); }); })(); + function dupRow(rowId, tableId) { + var dupEl; + var newEl; + + addRowTo(tableId); + for (i = 0; i < field_counter_js; i++) { + dupEl = document.getElementById(rowname[i] + rowId); + newEl = document.getElementById(rowname[i] + totalrows); + if (dupEl && newEl) + newEl.value = dupEl.value; + } + } + function removeRow(el) { var cel; + // Break out of one table first + while (el && el.nodeName.toLowerCase() != "table") + el = el.parentNode; while (el && el.nodeName.toLowerCase() != "tr") el = el.parentNode; @@ -343,15 +388,15 @@ include("head.inc"); rowname[0] = "acl_name"; rowtype[0] = "textbox"; - rowsize[0] = "30"; + rowsize[0] = "20"; rowname[1] = "acl_expression"; - rowtype[1] = "textbox"; - rowsize[1] = "35"; + rowtype[1] = "select"; + rowsize[1] = "10"; - rowname[2] = "acl_backend"; - rowtype[2] = "select"; - rowsize[2] = "10"; + rowname[2] = "acl_value"; + rowtype[2] = "textbox"; + rowsize[2] = "35"; function toggle_stats() { var stats_enabled=document.getElementById('stats_enabled'); @@ -359,29 +404,41 @@ include("head.inc"); var stats_username_row=document.getElementById('stats_username_row'); var stats_password_row=document.getElementById('stats_password_row'); var stats_uri_row=document.getElementById('stats_uri_row'); - var stats_node_enabled_row=document.getElementById('stats_node_enabled_row'); - var stats_node_row=document.getElementById('stats_node_row'); - var stats_desc_row=document.getElementById('stats_desc_row'); - var stats_desc_row=document.getElementById('stats_refresh_row'); if (stats_enabled.checked) { stats_realm_row.style.display=''; stats_username_row.style.display=''; stats_password_row.style.display=''; stats_uri_row.style.display=''; - stats_node_enabled_row.style.display=''; - stats_node_row.style.display=''; - stats_desc_row.style.display=''; - stats_refresh_row.style.display=''; } else { stats_realm_row.style.display='none'; stats_username_row.style.display='none'; stats_password_row.style.display='none'; stats_uri_row.style.display='none'; - stats_node_enabled_row.style.display='none'; - stats_node_row.style.display='none'; - stats_desc_row.style.display='none'; - stats_refresh_row.style.display='none'; + } + } + function type_change() { + var type, d, i, j, el, row; + var count = <?=count($a_acltypes);?>; + var acl = [ <?php foreach ($a_acltypes as $expr) echo "'".$expr['name']."'," ?> ]; + var mode = [ <?php foreach ($a_acltypes as $expr) echo "'".$expr['mode']."'," ?> ]; + + d = document; + type = d.getElementById("type").value; + for (i = 0; i < 99; i++) { + el = d.getElementById("acl_expression" + i); + row = d.getElementById("aclrow" + i); + if (!el) + continue; + for (j = 0; j < count; j++) { + if (acl[j] == el.value) { + if (mode[j] != '' && mode[j] != type) { + Effect.Fade(row,{ duration: 1.0 }); + } else { + Effect.Appear(row,{ duration: 1.0 }); + } + } + } } } </script> @@ -390,24 +447,165 @@ include("head.inc"); <?php if($one_two): ?> <p class="pgtitle"><?=$pgtitle?></p> <?php endif; ?> -<form action="haproxy_frontends_edit.php" method="post" name="iform" id="iform"> +<form action="haproxy_listeners_edit.php" method="post" name="iform" id="iform"> <table width="100%" border="0" cellpadding="6" cellspacing="0"> <tr> - <td colspan="2" valign="top" class="listtopic">Edit haproxy backend</td> - </tr> - <tr align="left"> + <td colspan="2" valign="top" class="listtopic">Edit haproxy listener</td> + </tr> + <tr> <td width="22%" valign="top" class="vncellreq">Name</td> <td width="78%" class="vtable" colspan="2"> <input name="name" type="text" <?if(isset($pconfig['name'])) echo "value=\"{$pconfig['name']}\"";?> size="25" maxlength="25"> </td> </tr> <tr align="left"> - <td width="22%" valign="top" class="vncellreq">Description</td> + <td width="22%" valign="top" class="vncell">Description</td> <td width="78%" class="vtable" colspan="2"> <input name="desc" type="text" <?if(isset($pconfig['desc'])) echo "value=\"{$pconfig['desc']}\"";?> size="64"> </td> </tr> <tr align="left"> + <td width="22%" valign="top" class="vncellreq">Status</td> + <td width="78%" class="vtable" colspan="2"> + <select name="status" id="status"> + <option value="active"<?php if($pconfig['status'] == "active") echo " SELECTED"; ?>>Active</option> + <option value="disabled"<?php if($pconfig['status'] == "disabled") echo " SELECTED"; ?>>Disabled</option> + </select> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncellreq">External address</td> + <td width="78%" class="vtable"> + <select name="extaddr" class="formfld"> + <option value="" <?php if (!$pconfig['extaddr']) echo "selected"; ?>>Interface address</option> + <?php + if (is_array($config['virtualip']['vip'])): + foreach ($config['virtualip']['vip'] as $sn): + ?> + <option value="<?=$sn['subnet'];?>" <?php if ($sn['subnet'] == $pconfig['extaddr']) echo "selected"; ?>> + <?=htmlspecialchars("{$sn['subnet']} ({$sn['descr']})");?> + </option> + <?php + endforeach; + endif; + ?> + <option value="any" <?php if($pconfig['extaddr'] == "any") echo "selected"; ?>>any</option> + </select> + <br /> + <span class="vexpl"> + If you want this rule to apply to another IP address than the IP address of the interface chosen above, + select it here (you need to define <a href="firewall_virtual_ip.php">Virtual IP</a> addresses on the first). + Also note that if you are trying to redirect connections on the LAN select the "any" option. + </span> + </td> + </tr> + <tr align="left"> + <td width="22%" valign="top" class="vncellreq">External port</td> + <td width="78%" class="vtable" colspan="2"> + <input name="port" type="text" <?if(isset($pconfig['port'])) echo "value=\"{$pconfig['port']}\"";?> size="10" maxlength="10"> + <div>The port to listen to. To specify multiple ports, separate with a comma (,). EXAMPLE: 80,443</div> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncellreq">Server pool</td> + <td width="78%" class="vtable"> + <select name="pool" class="formfld"> + <?php + if (is_array($a_pools)) { + foreach ($a_pools as $p): + ?> + <option value="<?=$p['name'];?>" <?php if ($p['name'] == $pconfig['pool']) echo "selected"; ?>> + <?=htmlspecialchars("{$p['name']}");?> + </option> + <?php + endforeach; + } else { + ?> + <option value="-">-</option> + <?php + } + ?> + </select> + <tr align="left"> + <td width="22%" valign="top" class="vncell">Server Port</td> + <td width="78%" class="vtable" colspan="2"> + <input name="svrport" type="text" <?if(isset($pconfig['svrport'])) echo "value=\"{$pconfig['svrport']}\"";?> size="10" maxlength="10"> + <div>The default server port.</div> + </td> + </tr> + <tr align="left"> + <td width="22%" valign="top" class="vncellreq">Type</td> + <td width="78%" class="vtable" colspan="2"> + <select name="type" id="type" onchange="type_change();"> + <option value="http"<?php if($pconfig['type'] == "http") echo " SELECTED"; ?>>HTTP</option> + <option value="https"<?php if($pconfig['type'] == "https") echo " SELECTED"; ?>>HTTPS</option> + <option value="tcp"<?php if($pconfig['type'] == "tcp") echo " SELECTED"; ?>>TCP</option> + <option value="health"<?php if($pconfig['type'] == "health") echo " SELECTED"; ?>>Health</option> + </select> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell">Access Control lists</td> + <td width="78%" class="vtable" colspan="2" valign="top"> + <table class="" width="100%" cellpadding="0" cellspacing="0" id='acltable'> + <tr> + <td width="35%" class="">Name</td> + <td width="40%" class="">Expression</td> + <td width="20%" class="">Value</td> + <td width="5%" class=""></td> + </tr> + <?php + $a_acl=$pconfig['a_acl']; + + if (!is_array($a_acl)) { + $a_acl=array(); + } + + $counter=0; + foreach ($a_acl as $acl) { + $t = haproxy_find_acl($acl['expression']); + $display = ''; + if (!$t || ($t['mode'] != '' && $t['mode'] != strtolower($pconfig['type']))) + $display = 'style="display: none;"'; + ?> + <tr id="aclrow<?=$counter;?>" <?=$display;?>> + <td><input name="acl_name<?=$counter;?>" id="acl_name<?=$counter;?>" type="text" value="<?=$acl['name']; ?>" size="20"/></td> + <td> + <select name="acl_expression<?=$counter;?>" id="acl_expression<?=$counter;?>"> + <?php + foreach ($a_acltypes as $expr) { ?> + <option value="<?=$expr['name'];?>"<?php if($acl['expression'] == $expr['name']) echo " SELECTED"; ?>><?=$expr['descr'];?>:</option> + <?php } ?> + </select> + </td> + <td><input name="acl_value<?=$counter;?>" id="acl_value<?=$counter;?>" type="text" value="<?=$acl['value']; ?>" size="35"/></td> + <td class="list"> + <table border="0" cellspacing="0" cellpadding="1"><tr> + <td valign="middle"> + <img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" title="delete entry" width="17" height="17" border="0" onclick="removeRow(this); return false;"> + </td> + <td valign="middle"> + <img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" title="duplicate entry" width="17" height="17" border="0" onclick="dupRow(<?=$counter;?>, 'acltable'); return false;"> + </td></tr></table> + </td> + </tr> + <?php + $counter++; + } + ?> + </table> + <a onclick="javascript:addRowTo('acltable'); return false;" href="#"> + <img border="0" src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" alt="" title="add another entry" /> + </a><br/> + For more information about ACL's please see <a href='http://haproxy.1wt.eu/download/1.3/doc/configuration.txt' target='_new'>HAProxy Documentation</a> Section 7 - Using ACL's + </td> + </tr> + </table> + <table width="100%" border="0" cellpadding="6" cellspacing="0"> + <tr> + <td colspan="2" valign="top" class="listtopic">Advanced settings</td> + </tr> + <tr align="left"> <td width="22%" valign="top" class="vncellreq">Connection timeout</td> <td width="78%" class="vtable" colspan="2"> <input name="connection_timeout" type="text" <?if(isset($pconfig['connection_timeout'])) echo "value=\"{$pconfig['connection_timeout']}\"";?> size="64"> @@ -432,23 +630,12 @@ set by the 'retries' parameter (2).</div> </td> </tr> <tr align="left"> - <td width="22%" valign="top" class="vncellreq">Type</td> - <td width="78%" class="vtable" colspan="2"> - <select name="type" id="type" onchange="type_change();"> - <option value="http"<?php if($pconfig['type'] == "http") echo " SELECTED"; ?>>HTTP</option> - <option value="https"<?php if($pconfig['type'] == "https") echo " SELECTED"; ?>>HTTPS</option> - <option value="tcp"<?php if($pconfig['type'] == "tcp") echo " SELECTED"; ?>>TCP</option> - <option value="health"<?php if($pconfig['type'] == "health") echo " SELECTED"; ?>>Health</option> - </select> - </td> - </tr> - <tr align="left"> <td width="22%" valign="top" class="vncellreq">Balance</td> <td width="78%" class="vtable" colspan="2"> <table width="100%"> <tr> <td width="20%" valign="top"> - <input type="radio" name="balance" id="balance" value="roundrobin"<?php if($pconfig['balance'] == "roundrobin") echo " CHECKED"; ?>>Round robin</input> + <input type="radio" name="balance" id="balance" value="roundrobin"<?php if($pconfig['balance'] == "roundrobin") echo " CHECKED"; ?>>Round robin </td> <td> Each server is used in turns, according to their weights. @@ -458,38 +645,8 @@ set by the 'retries' parameter (2).</div> on the fly for slow starts for instance. </td> </tr> - <tr> - <td width="20%" valign="top"> - <input type="radio" name="balance" id="balance" value="static-rr"<?php if($pconfig['balance'] == "static-rr") echo " CHECKED"; ?>>Static Round Robin</input> - </td> - <td> - Each server is used in turns, according to their weights. - This algorithm is as similar to roundrobin except that it is - static, which means that changing a server's weight on the - fly will have no effect. On the other hand, it has no design - limitation on the number of servers, and when a server goes - up, it is always immediately reintroduced into the farm, once - the full map is recomputed. It also uses slightly less CPU to - run (around -1%). - </td> - </tr> - <tr> - <td width="20%" valign="top"> - <input type="radio" name="balance" id="balance" value="leastconn"<?php if($pconfig['balance'] == "leastconn") echo " CHECKED"; ?>>Least Connections</input> - </td> - <td> - The server with the lowest number of connections receives the - connection. Round-robin is performed within groups of servers - of the same load to ensure that all servers will be used. Use - of this algorithm is recommended where very long sessions are - expected, such as LDAP, SQL, TSE, etc... but is not very well - suited for protocols using short sessions such as HTTP. This - algorithm is dynamic, which means that server weights may be - adjusted on the fly for slow starts for instance. - </td> - </tr> <tr><td valign="top"><input type="radio" name="balance" id="balance" value="source"<?php if($pconfig['balance'] == -"source") echo " CHECKED"; ?>>Source</input></td><td> +"source") echo " CHECKED"; ?>>Source</td><td> The source IP address is hashed and divided by the total weight of the running servers to designate which server will receive the request. This ensures that the same client IP @@ -541,140 +698,20 @@ set by the 'retries' parameter (2).</div> <br/> </td> </tr> - <tr align="left" id='stats_node_enabled_row' name='stats_node_enabled_row' <?if ($pconfig['stats_enabled']!='yes') echo "style=\"display: none;\"";?>> - <td width="22%" valign="top" class="vncell">Stats Enable Node Name</td> - <td width="78%" class="vtable" colspan="2"> - <input id="stats_node_enabled" name="stats_node_enabled" type="checkbox" value="yes" <?php if ($pconfig['stats_node_enabled']=='yes') echo "checked"; ?>> - <br/> - </td> - </tr> - <tr align="left" id='stats_node_row' name='stats_node_row' <?if ($pconfig['stats_enabled']!='yes') echo "style=\"display: none;\"";?>> - <td width="22%" valign="top" class="vncell">Stats Node</td> - <td width="78%" class="vtable" colspan="2"> - <input id="stats_node" name="stats_node" type="text" <?if(isset($pconfig['stats_node'])) echo "value=\"{$pconfig['stats_node']}\"";?> size="64"><br/> - The node name is displayed in the stats and helps to differentiate which server in a cluster is actually serving clients.<br/> - Leave blank to use the system name. - </td> - </tr> - <tr align="left" id='stats_desc_row' name='stats_desc_row' <?if ($pconfig['stats_enabled']!='yes') echo "style=\"display: none;\"";?>> - <td width="22%" valign="top" class="vncell">Stats Description</td> - <td width="78%" class="vtable" colspan="2"> - <input id="stats_desc" name="stats_desc" type="text" <?if(isset($pconfig['stats_node'])) echo "value=\"{$pconfig['stats_desc']}\"";?> size="64"><br/> - </td> - </tr> - <tr align="left" id='stats_refresh_row' name='stats_refresh_row' <?if ($pconfig['stats_enabled']!='yes') echo "style=\"display: none;\"";?>> - <td width="22%" valign="top" class="vncell">Stats Refresh</td> - <td width="78%" class="vtable" colspan="2"> - <input id="stats_refresh" name="stats_refresh" type="text" <?if(isset($pconfig['stats_refresh'])) echo "value=\"{$pconfig['stats_refresh']}\"";?> size="10" maxlength="30"><br/> - Specify the refresh rate of the stats page in seconds, or specified time unit (us, ms, s, m, h, d). - </td> - </tr> - <tr align="left"> - <td width="22%" valign="top" id="monitorport_text" class="vncell">Monitor Uri</td> - <td width="78%" class="vtable" colspan="2"> - <input name="monitor_uri" type="text" <?if(isset($pconfig['monitor_uri'])) echo "value=\"{$pconfig['monitor_uri']}\"";?> size="50" maxlength="50"> - <br/> - Example: / or /index.php or /index.html or /testmypage.cgi - </td> - </tr> - </tr> <tr align="left"> - <td width="22%" valign="top" class="vncellreq">Port</td> - <td width="78%" class="vtable" colspan="2"> - <input name="port" type="text" <?if(isset($pconfig['port'])) echo "value=\"{$pconfig['port']}\"";?> size="30" maxlength="500"> - <div>The port to listen to. To specify multiple ports, separate with a comma (,). EXAMPLE: 80,443</div> - </td> - </tr> - <tr> - <td width="22%" valign="top" class="vncellreq">External address</td> - <td width="78%" class="vtable"> - <select name="extaddr" class="formfld"> - <option value="" <?php if (!$pconfig['extaddr']) echo "selected"; ?>>Interface address</option> - <?php - if (is_array($config['virtualip']['vip'])): - foreach ($config['virtualip']['vip'] as $sn): - ?> - <option value="<?=$sn['subnet'];?>" <?php if ($sn['subnet'] == $pconfig['extaddr']) echo "selected"; ?>> - <?=htmlspecialchars("{$sn['subnet']} ({$sn['descr']})");?> - </option> - <?php - endforeach; - endif; - ?> - <option value="any" <?php if($pconfig['extaddr'] == "any") echo "selected"; ?>>any</option> - </select> - <br /> - <span class="vexpl"> - If you want this rule to apply to another IP address than the IP address of the interface chosen above, - select it here (you need to define <a href="firewall_virtual_ip.php">Virtual IP</a> addresses on the first). - Also note that if you are trying to redirect connections on the LAN select the "any" option. - </span> - </td> - </tr> - <tr align="left"> - <td width="22%" valign="top" class="vncell">Max connections</td> + <td width="22%" valign="top" class="vncellreq">Max connections</td> <td width="78%" class="vtable" colspan="2"> <input name="max_connections" type="text" <?if(isset($pconfig['max_connections'])) echo "value=\"{$pconfig['max_connections']}\"";?> size="10" maxlength="10"> </td> </tr> <tr align="left"> - <td width="22%" valign="top" class="vncell">Client timeout</td> + <td width="22%" valign="top" class="vncellreq">Client timeout</td> <td width="78%" class="vtable" colspan="2"> <input name="client_timeout" type="text" <?if(isset($pconfig['client_timeout'])) echo "value=\"{$pconfig['client_timeout']}\"";?> size="10" maxlength="10"> <div>the time (in milliseconds) we accept to wait for data from the client, or for the client to accept data (30000).</div> </td> </tr> <?php -/* - <tr> - <td width="22%" valign="top" class="vncell">Access Control lists</td> - <td width="78%" class="vtable" colspan="2" valign="top"> - <table class="" width="100%" cellpadding="0" cellspacing="0" id='acltable'> - <tr> - <td width="35%" class="">Name</td> - <td width="40%" class="">Expression</td> - <td width="20%" class="">Backend</td> - <td width="5%" class=""></td> - </tr> - <?php - $a_acl=$pconfig['a_acl']; - - if (!is_array($a_acl)) { - $a_acl=array(); - } - - $i=0; - foreach ($a_acl as $acl) { - ?> - <tr> - <td><input name="acl_name<?=$i;?>" type="text" value="<?=$acl['name']; ?>" size="30"/></td> - <td><input name="acl_expression<?=$i;?>" type="text" value="<?=$acl['expression']; ?>" size="35"/></td> - <td> - <select name="acl_backend<?=$i;?>" id="acl_backend<?=$i;?>"> - <?php - if (!is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) { - $config['installedpackages']['haproxy']['ha_backends']['item'] = array(); - } - $a_backend = &$config['installedpackages']['haproxy']['ha_backends']['item']; - foreach ($a_backend as $backend) { ?> - <option value="<?=$backend['name'];?>"<?php if($acl['backend'] == $backend['name']) echo " SELECTED"; ?>><?=$backend['name'];?></option> - <?php $i++; } ?> - </select> - </td> - <td class="list"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0" onclick="removeRow(this); return false;"></td> - </tr> - <?php - $i++; - } - ?> - </table> - <a onclick="javascript:addRowTo('acltable'); return false;" href="#"> - <img border="0" src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" alt="" title="add another entry" /> - </a><br/> - Fore more information about ACL's please see <a href='http://haproxy.1wt.eu/download/1.3/doc/configuration.txt' target='_new'>HAProxy Documentation</a> Section 7 - Using ACL's - </td> - </tr> -*/ ?> <tr align="left"> <td width="22%" valign="top" class="vncell">Use 'forwardfor' option</td> @@ -726,9 +763,8 @@ set by the 'retries' parameter (2).</div> <script type="text/javascript"> field_counter_js = 3; rows = 1; - <?php $counter=0; ?> - totalrows = <?php echo $counter; ?>;; - loaded = <?php echo $counter; ?>;; + totalrows = <?php echo $counter; ?>; + loaded = <?php echo $counter; ?>; </script> <?php include("fend.inc"); ?> </body> diff --git a/config/haproxy/haproxy_pool_edit.php b/config/haproxy/haproxy_pool_edit.php new file mode 100755 index 00000000..d25f0675 --- /dev/null +++ b/config/haproxy/haproxy_pool_edit.php @@ -0,0 +1,494 @@ +<?php +/* $Id: load_balancer_pool_edit.php,v 1.24.2.23 2007/03/03 00:07:09 smos Exp $ */ +/* + haproxy_pool_edit.php + part of pfSense (http://www.pfsense.com/) + Copyright (C) 2009 Scott Ullrich <sullrich@pfsense.com> + Copyright (C) 2008 Remco Hoef <remcoverhoef@pfsense.com> + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +require("guiconfig.inc"); + +$d_haproxyconfdirty_path = $g['varrun_path'] . "/haproxy.conf.dirty"; + +if (!is_array($config['installedpackages']['haproxy']['ha_pools']['item'])) { + $config['installedpackages']['haproxy']['ha_pools']['item'] = array(); +} + +$a_pools = &$config['installedpackages']['haproxy']['ha_pools']['item']; + +if (isset($_POST['id'])) + $id = $_POST['id']; +else + $id = $_GET['id']; + +if (isset($_GET['dup'])) + $id = $_GET['dup']; + +if (isset($id) && $a_pools[$id]) { + $pconfig['name'] = $a_pools[$id]['name']; + $pconfig['checkinter'] = $a_pools[$id]['checkinter']; + $pconfig['monitor_uri'] = $a_pools[$id]['monitor_uri']; + $pconfig['cookie'] = $a_pools[$id]['cookie']; + $pconfig['advanced'] = base64_decode($a_pools[$id]['advanced']); + $pconfig['a_servers']=&$a_pools[$id]['ha_servers']['item']; +} + +if (isset($_GET['dup'])) + unset($id); + +$changedesc = "Services: HAProxy: pools: "; +$changecount = 0; + +if ($_POST) { + $changecount++; + + unset($input_errors); + $pconfig = $_POST; + + $reqdfields = explode(" ", "name"); + $reqdfieldsn = explode(",", "Name"); + + do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors); + + if (preg_match("/[^a-zA-Z0-9\.\-_]/", $_POST['name'])) + $input_errors[] = "The field 'Name' contains invalid characters."; + + /* Ensure that our pool names are unique */ + for ($i=0; isset($config['installedpackages']['haproxy']['ha_pools']['item'][$i]); $i++) + if (($_POST['name'] == $config['installedpackages']['haproxy']['ha_pools']['item'][$i]['name']) && ($i != $id)) + $input_errors[] = "This pool name has already been used. Pool names must be unique."; + + $a_servers=array(); + for($x=0; $x<99; $x++) { + $server_name=$_POST['server_name'.$x]; + $server_address=$_POST['server_address'.$x]; + $server_port=$_POST['server_port'.$x]; + $server_weight=$_POST['server_weight'.$x]; + $server_backup=$_POST['server_backup'.$x]; + + if ($server_address) { + + $server=array(); + $server['name']=$server_name; + $server['address']=$server_address; + $server['port']=$server_port; + $server['weight']=$server_weight; + $server['backup']=$server_backup; + $a_servers[]=$server; + + if (preg_match("/[^a-zA-Z0-9\.\-_]/", $server_name)) + $input_errors[] = "The field 'Name' contains invalid characters."; + if (preg_match("/[^a-zA-Z0-9\.\-_]/", $server_address)) + $input_errors[] = "The field 'Address' contains invalid characters."; + + if (!preg_match("/.{2,}/", $server_name)) + $input_errors[] = "The field 'Name' is required."; + + if (!preg_match("/.{2,}/", $server_address)) + $input_errors[] = "The field 'Address' is required."; + + if (!preg_match("/.{2,}/", $server_weight)) + $input_errors[] = "The field 'Weight' is required."; + + if (!is_numeric($server_weight)) + $input_errors[] = "The field 'Weight' value is not a number."; + if ($server_port && !is_numeric($server_port)) + $input_errors[] = "The field 'Port' value is not a number."; + } + } + + if (!$input_errors) { + $pool = array(); + if(isset($id) && $a_pools[$id]) + $pool = $a_pools[$id]; + + if ($pool['name'] != $_POST['name']) { + // name changed: + if (!is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) { + $config['installedpackages']['haproxy']['ha_backends']['item'] = array(); + } + $a_backend = &$config['installedpackages']['haproxy']['ha_backends']['item']; + + for ( $i = 0; $i < count($a_backend); $i++) { + if ($a_backend[$i]['pool'] == $pool['name']) + $a_backend[$i]['pool'] = $_POST['name']; + } + } + + if($pool['name'] != "") + $changedesc .= " modified '{$pool['name']}' pool:"; + + $pool['ha_servers']['item']=$a_servers; + + update_if_changed("name", $pool['name'], $_POST['name']); + update_if_changed("cookie", $pool['cookie'], $_POST['cookie']); + update_if_changed("advanced", $pool['advanced'], base64_encode($_POST['advanced'])); + update_if_changed("checkinter", $pool['checkinter'], $_POST['checkinter']); + update_if_changed("monitor_uri", $pool['monitor_uri'], $_POST['monitor_uri']); + + if (isset($id) && $a_pools[$id]) { + $a_pools[$id] = $pool; + } else { + $a_pools[] = $pool; + } + + if ($changecount > 0) { + touch($d_haproxyconfdirty_path); + write_config($changedesc); + /* + echo "<PRE>"; + print_r($config); + echo "</PRE>"; + */ + } + + header("Location: haproxy_pools.php"); + exit; + } + $pconfig['a_servers']=&$a_pools[$id]['ha_servers']['item']; +} + +$pfSversion = str_replace("\n", "", file_get_contents("/etc/version")); +if(strstr($pfSversion, "1.2")) + $one_two = true; + +$pgtitle = "HAProxy: pool: Edit"; +include("head.inc"); + +row_helper(); + +?> + +<input type='hidden' name='address_type' value='textbox' /> + +<body link="#0000CC" vlink="#0000CC" alink="#0000CC"> +<script type="text/javascript" language="javascript" src="pool.js"></script> + +<script language="javascript"> +function clearcombo(){ + for (var i=document.iform.serversSelect.options.length-1; i>=0; i--){ + document.iform.serversSelect.options[i] = null; + } + document.iform.serversSelect.selectedIndex = -1; +} +</script> +<script type="text/javascript"> + rowname[0] = "server_name"; + rowtype[0] = "textbox"; + rowsize[0] = "30"; + rowname[1] = "server_address"; + rowtype[1] = "textbox"; + rowsize[1] = "30"; + rowname[2] = "server_port"; + rowtype[2] = "textbox"; + rowsize[2] = "5"; + rowname[3] = "server_weight"; + rowtype[3] = "textbox"; + rowsize[3] = "5"; + rowname[4] = "server_backup"; + rowtype[4] = "checkbox"; + rowsize[4] = "5"; +</script> +<?php include("fbegin.inc"); ?> +<?php if ($input_errors) print_input_errors($input_errors); ?> +<?php if($one_two): ?> +<p class="pgtitle"><?=$pgtitle?></p> +<?php endif; ?> + <form action="haproxy_pool_edit.php" method="post" name="iform" id="iform"> + <table width="100%" border="0" cellpadding="6" cellspacing="0"> + <tr> + <td colspan="2" valign="top" class="listtopic">Edit HAProxy pool</td> + </tr> + <tr align="left"> + <td width="22%" valign="top" class="vncellreq">Name</td> + <td width="78%" class="vtable" colspan="2"> + <input name="name" type="text" <?if(isset($pconfig['name'])) echo "value=\"{$pconfig['name']}\"";?> size="16" maxlength="16"> + </td> + </tr> + <tr align="left"> + <td width="22%" valign="top" class="vncell">Cookie</td> + <td width="78%" class="vtable" colspan="2"> + <input name="cookie" type="text" <?if(isset($pconfig['cookie'])) echo "value=\"{$pconfig['cookie']}\"";?>size="64"><br/> + This value will be checked in incoming requests, and the first + operational pool possessing the same value will be selected. In return, in + cookie insertion or rewrite modes, this value will be assigned to the cookie + sent to the client. There is nothing wrong in having several servers sharing + the same cookie value, and it is in fact somewhat common between normal and + backup servers. See also the "cookie" keyword in backend section. + + </td> + </tr> + <tr align="left"> + <td class="vncellreq" colspan="3">Server list</td> + </tr> + <tr> + <td width="78%" class="vtable" colspan="2" valign="top"> + <table class="" width="100%" cellpadding="0" cellspacing="0" id='servertable'> + <tr> + <td width="30%" class="">Name</td> + <td width="30%" class="">Address</td> + <td width="18%" class="">Port</td> + <td width="18%" class="">Weight</td> + <td width="5%" class="">Backup</td> + <td width="4%" class=""></td> + </tr> + <?php + $a_servers=$pconfig['a_servers']; + + if (!is_array($a_servers)) { + $a_servers=array(); + } + + $counter=0; + foreach ($a_servers as $server) { + ?> + <tr id="tr_view_<?=$counter;?>" name="tr_view_<?=$counter;?>"> + <td class="vtable"><?=$server['name']; ?></td> + <td class="vtable"><?=$server['address']; ?></td> + <td class="vtable"><?=$server['port']; ?></td> + <td class="vtable"><?=$server['weight']; ?></td> + <td class="vtable"><?=$server['backup']; ?></td> + <td class="list"> + <table border="0" cellspacing="0" cellpadding="1"><tr> + <td valign="middle"> + <img src="/themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" title="edit entry" width="17" height="17" border="0" onclick="editRow(<?=$counter;?>); return false;"> + </td> + <td valign="middle"> + <img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" title="duplicate entry" width="17" height="17" border="0" onclick="dupRow(<?=$counter;?>, 'servertable'); return false;"> + </td></tr></table> + </td> + </tr> + <tr id="tr_edit_<?=$counter;?>" name="tr_edit_<?=$counter;?>" style="display: none;"> + <td class="vtable"> + <input name="server_name<?=$counter;?>" id="server_name<?=$counter;?>" type="text" value="<?=$server['name']; ?>" size="30"/></td> + <td class="vtable"> + <input name="server_address<?=$counter;?>" id="server_address<?=$counter;?>" type="text" value="<?=$server['address']; ?>" size="30"/></td> + <td class="vtable"> + <input name="server_port<?=$counter;?>" id="server_port<?=$counter;?>" type="text" value="<?=$server['port']; ?>" size="5"/></td> + <td class="vtable"> + <input name="server_weight<?=$counter;?>" id="server_weight<?=$counter;?>" type="text" value="<?=$server['weight']; ?>" size="5"/></td> + <td class="vtable"> + <input name="server_backup<?=$counter;?>" id="server_backup<?=$counter;?>" type="checkbox" value="yes" <?php if ($server['backup']=='yes') echo "checked"; ?>/></td> + <td class="list"> + <table border="0" cellspacing="0" cellpadding="1"><tr> + <td valign="middle"> + <img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" title="delete entry" width="17" height="17" border="0" onclick="removeRow(this); return false;"> + </td> + <td valign="middle"> + <img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" title="duplicate entry" width="17" height="17" border="0" onclick="dupRow(<?=$counter;?>, 'servertable'); return false;"> + </td></tr></table> + </td> + </tr> + <?php + $counter++; + } + ?> + </table> + <a onclick="javascript:addRowTo('servertable'); return false;" href="#"> + <img border="0" src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" alt="" title="add another entry" /> + </a> + </td> + </tr> + <tr align="left"> + <td width="22%" valign="top" class="vncell">Check freq</td> + <td width="78%" class="vtable" colspan="2"> + <input name="checkinter" type="text" <?if(isset($pconfig['checkinter'])) echo "value=\"{$pconfig['checkinter']}\"";?>size="20"> milliseconds + <br/>Defaults to 1000 if left blank. + </td> + </tr> + <tr align="left"> + <td width="22%" valign="top" class="vncell">Health check URI</td> + <td width="78%" class="vtable" colspan="2"> + <input name="monitor_uri" type="text" <?if(isset($pconfig['monitor_uri'])) echo "value=\"{$pconfig['monitor_uri']}\"";?>size="64"> + <br/>Defaults to / if left blank. + </td> + </tr> + <tr align="left"> + <td width="22%" valign="top" class="vncell">Advanced pass thru</td> + <td width="78%" class="vtable" colspan="2"> + <textarea name='advanced' rows="4" cols="70" id='advanced'><?php echo $pconfig['advanced']; ?></textarea> + <br/> + NOTE: paste text into this box that you would like to pass thru. + </td> + </tr> + <tr align="left"> + <td width="22%" valign="top"> </td> + <td width="78%"> + <input name="Submit" type="submit" class="formbtn" value="Save"> + <input type="button" class="formbtn" value="Cancel" onclick="history.back()"> + <?php if (isset($id) && $a_pools[$id]): ?> + <input name="id" type="hidden" value="<?=$id;?>"> + <?php endif; ?> + </td> + </tr> + </table> + </form> +<br> +<?php include("fend.inc"); ?> +<script type="text/javascript"> + field_counter_js = 5; + rows = 1; + totalrows = <?php echo $counter; ?>; + loaded = <?php echo $counter; ?>; +</script> +</body> +</html> + +<?php + +function row_helper() { + echo <<<EOF +<script type="text/javascript"> +// Global Variables +var rowname = new Array(99); +var rowtype = new Array(99); +var newrow = new Array(99); +var rowsize = new Array(99); + +for (i = 0; i < 99; i++) { + rowname[i] = ''; + rowtype[i] = ''; + newrow[i] = ''; + rowsize[i] = '25'; +} + +var field_counter_js = 0; +var loaded = 0; +var is_streaming_progress_bar = 0; +var temp_streaming_text = ""; + +var addRowTo = (function() { + return (function (tableId) { + var d, tbody, tr, td, bgc, i, ii, j; + var btable, btbody, btr, btd; + + d = document; + tbody = d.getElementById(tableId).getElementsByTagName("tbody").item(0); + tr = d.createElement("tr"); + totalrows++; + for (i = 0; i < field_counter_js; i++) { + td = d.createElement("td"); + if(rowtype[i] == 'textbox') { + td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + + "'></input><input size='" + rowsize[i] + "' name='" + rowname[i] + totalrows + + "' id='" + rowname[i] + totalrows + "'></input> "; + } else if(rowtype[i] == 'select') { + td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + + "'></input><select size='" + rowsize[i] + "' name='" + rowname[i] + totalrows + + "' id='" + rowname[i] + totalrows + "'>$options</select> "; + } else { + td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + + "'></input><input type='checkbox' name='" + rowname[i] + totalrows + + "' id='" + rowname[i] + totalrows + "' value='yes'></input> "; + } + td.setAttribute("class","vtable"); + tr.appendChild(td); + } + td = d.createElement("td"); + td.rowSpan = "1"; + td.setAttribute("class","list"); + + // Recreate the button table. + btable = document.createElement("table"); + btable.setAttribute("border", "0"); + btable.setAttribute("cellspacing", "0"); + btable.setAttribute("cellpadding", "1"); + btbody = document.createElement("tbody"); + btr = document.createElement("tr"); + btd = document.createElement("td"); + btd.setAttribute("valign", "middle"); + btd.innerHTML = '<img src="/themes/' + theme + '/images/icons/icon_x.gif" title="delete entry" width="17" height="17" border="0" onclick="removeRow(this); return false;">'; + btr.appendChild(btd); + btd = document.createElement("td"); + btd.setAttribute("valign", "middle"); + btd.innerHTML = '<img src="/themes/' + theme + "/images/icons/icon_plus.gif\" title=\"duplicate entry\" width=\"17\" height=\"17\" border=\"0\" onclick=\"dupRow(" + totalrows + ", 'servertable'); return false;\">"; + btr.appendChild(btd); + btbody.appendChild(btr); + btable.appendChild(btbody); + + td.appendChild(btable); + tr.appendChild(td); + tbody.appendChild(tr); + }); +})(); + +function dupRow(rowId, tableId) { + var dupEl; + var newEl; + + addRowTo(tableId); + for (i = 0; i < field_counter_js; i++) { + dupEl = document.getElementById(rowname[i] + rowId); + newEl = document.getElementById(rowname[i] + totalrows); + if (dupEl && newEl) + if(rowtype[i] == 'checkbox') + newEl.checked = dupEl.checked; + else + newEl.value = dupEl.value; + } +} + +function removeRow(el) { + var cel; + // Break out of one table first + while (el && el.nodeName.toLowerCase() != "table") + el = el.parentNode; + while (el && el.nodeName.toLowerCase() != "tr") + el = el.parentNode; + + if (el && el.parentNode) { + cel = el.getElementsByTagName("td").item(0); + el.parentNode.removeChild(el); + } +} +function editRow(num) { + var trview = document.getElementById('tr_view_' + num); + var tredit = document.getElementById('tr_edit_' + num); + + trview.style.display='none'; + tredit.style.display=''; +} + +function find_unique_field_name(field_name) { + // loop through field_name and strip off -NUMBER + var last_found_dash = 0; + for (var i = 0; i < field_name.length; i++) { + // is this a dash, if so, update + // last_found_dash + if (field_name.substr(i,1) == "-" ) + last_found_dash = i; + } + if (last_found_dash < 1) + return field_name; + return(field_name.substr(0,last_found_dash)); +} +</script> + +EOF; + +} + +?> diff --git a/config/haproxy/haproxy_servers.php b/config/haproxy/haproxy_pools.php index cacf995a..c5adc70b 100755 --- a/config/haproxy/haproxy_servers.php +++ b/config/haproxy/haproxy_pools.php @@ -1,7 +1,7 @@ <?php /* $Id: load_balancer_virtual_server.php,v 1.6.2.1 2006/01/02 23:46:24 sullrich Exp $ */ /* - haproxy_servers.php + haproxy_pools.php part of pfSense (http://www.pfsense.com/) Copyright (C) 2009 Scott Ullrich <sullrich@pfsense.com> Copyright (C) 2008 Remco Hoef <remcoverhoef@pfsense.com> @@ -34,11 +34,14 @@ require_once("haproxy.inc"); $d_haproxyconfdirty_path = $g['varrun_path'] . "/haproxy.conf.dirty"; -if (!is_array($config['installedpackages']['haproxy']['ha_servers']['item'])) { - $config['installedpackages']['haproxy']['ha_servers']['item'] = array(); +if (!is_array($config['installedpackages']['haproxy']['ha_pools']['item'])) { + $config['installedpackages']['haproxy']['ha_pools']['item'] = array(); +} +if (!is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) { + $config['installedpackages']['haproxy']['ha_backends']['item'] = array(); } -$a_server = &$config['installedpackages']['haproxy']['ha_servers']['item']; +$a_pools = &$config['installedpackages']['haproxy']['ha_pools']['item']; $a_backends = &$config['installedpackages']['haproxy']['ha_backends']['item']; if ($_POST) { @@ -55,22 +58,20 @@ if ($_POST) { } if ($_GET['act'] == "del") { - if ($a_server[$_GET['id']]) { - if (!$input_errors) { - unset($a_server[$_GET['id']]); - write_config(); - touch($d_haproxyconfdirty_path); - header("Location: haproxy_servers.php"); - exit; - } + if (isset($a_pools[$_GET['id']])) { + unset($a_pools[$_GET['id']]); + write_config(); + touch($d_haproxyconfdirty_path); } + header("Location: haproxy_pools.php"); + exit; } $pfSversion = str_replace("\n", "", file_get_contents("/etc/version")); if(strstr($pfSversion, "1.2")) $one_two = true; -$pgtitle = "Services: HAProxy: Servers"; +$pgtitle = "Services: HAProxy: Server pools"; include("head.inc"); ?> @@ -79,21 +80,21 @@ include("head.inc"); <?php if($one_two): ?> <p class="pgtitle"><?=$pgtitle?></p> <?php endif; ?> -<form action="haproxy_servers.php" method="post"> +<form action="haproxy_pools.php" method="post"> <?php if ($input_errors) print_input_errors($input_errors); ?> <?php if ($savemsg) print_info_box($savemsg); ?> <?php if (file_exists($d_haproxyconfdirty_path)): ?><p> -<?php print_info_box_np("The virtual server configuration has been changed.<br>You must apply the changes in order for them to take effect.");?><br> +<?php print_info_box_np("The virtual pool configuration has been changed.<br>You must apply the changes in order for them to take effect.");?><br> <?php endif; ?> <table width="100%" border="0" cellpadding="0" cellspacing="0"> <tr><td class="tabnavtbl"> <?php /* active tabs */ $tab_array = array(); - $tab_array[] = array("Settings", false, "haproxy_global.php"); - $tab_array[] = array("Frontends", false, "haproxy_frontends.php"); - $tab_array[] = array("Servers", true, "haproxy_servers.php"); - display_top_tabs($tab_array); + $tab_array[] = array("Settings", false, "haproxy_global.php"); + $tab_array[] = array("Listener", false, "haproxy_listeners.php"); + $tab_array[] = array("Server Pool", true, "haproxy_pools.php"); + display_top_tabs($tab_array); ?> </td></tr> <tr> @@ -102,60 +103,59 @@ include("head.inc"); <table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0"> <tr> <td width="30%" class="listhdrr">Name</td> - <td width="30%" class="listhdrr">Server</td> - <td width="20%" class="listhdrr">Status</td> - <td width="30%" class="listhdrr">Frontend</td> - <td width="10%" class="listhdrr">Cookie</td> - <td width="10%" class="listhdrr">Weight</td> + <td width="10%" class="listhdrr">Servers</td> + <td width="40%" class="listhdrr">Listener</td> <td width="10%" class="list"></td> </tr> - <?php $i = 0; foreach ($a_server as $server): ?> - <tr> - <td class="listlr" ondblclick="document.location='haproxy_servers_edit.php?id=<?=$i;?>';"> - <?=$server['name'];?> - </td> - <td class="listlr" ondblclick="document.location='haproxy_servers_edit.php?id=<?=$i;?>';"> - <?=$server['address'] . ":"?> <?php - if($server['port']) { - echo $server['port']; - } else { - foreach ($a_backends as $backend) { - if($backend['name'] == $server['backend']) { - echo $backend['port']; - } - } - } + $i = 0; + foreach ($a_pools as $pool): + + $fe_list = ""; + $sep = ""; + foreach ($a_backends as $backend) { + if($backend['pool'] == $pool['name']) { + $fe_list .= $sep . $backend['name']; + $sep = ", "; + } + } + $textss = $textse = ""; + if ($fe_list == "") { + $textss = "<span class=\"gray\">"; + $textse = "</span>"; + } + if (is_array($pool['ha_servers']['item'])) + $count = count($pool['ha_servers']['item']); + else + $count = 0; ?> + <tr> + <td class="listlr" ondblclick="document.location='haproxy_pool_edit.php?id=<?=$i;?>';"> + <?=$textss . $pool['name'] . $textse;?> </td> - <td class="listlr" ondblclick="document.location='haproxy_servers_edit.php?id=<?=$i;?>';"> - <?=$server['status'];?> - </td> - <td class="listlr" ondblclick="document.location='haproxy_servers_edit.php?id=<?=$i;?>';"> - <?=$server['backend'];?> - </td> - <td class="listlr" ondblclick="document.location='haproxy_servers_edit.php?id=<?=$i;?>';"> - <?=$server['cookie'];?> + <td class="listlr" ondblclick="document.location='haproxy_pool_edit.php?id=<?=$i;?>';"> + <?=$textss . $count . $textse;?> </td> - <td class="listlr" ondblclick="document.location='haproxy_servers_edit.php?id=<?=$i;?>';"> - <?=$server['weight'];?> + <td class="listlr" ondblclick="document.location='haproxy_pool_edit.php?id=<?=$i;?>';"> + <?=$textss . $fe_list . $textse;?> </td> <td class="list" nowrap> <table border="0" cellspacing="0" cellpadding="1"> <tr> - <td valign="middle"><a href="haproxy_servers_edit.php?id=<?=$i;?>"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" width="17" height="17" border="0"></a></td> - <td valign="middle"><a href="haproxy_servers.php?act=del&id=<?=$i;?>" onclick="return confirm('Do you really want to delete this entry?')"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0"></a></td> + <td valign="middle"><a href="haproxy_pool_edit.php?id=<?=$i;?>"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" width="17" height="17" border="0"></a></td> + <td valign="middle"><a href="haproxy_pools.php?act=del&id=<?=$i;?>" onclick="return confirm('Do you really want to delete this entry?')"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0"></a></td> + <td valign="middle"><a href="haproxy_pool_edit.php?dup=<?=$i;?>"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0"></a></td> </tr> </table> </td> </tr> <?php $i++; endforeach; ?> <tr> - <td class="list" colspan="6"></td> + <td class="list" colspan="3"></td> <td class="list"> <table border="0" cellspacing="0" cellpadding="1"> <tr> - <td valign="middle"><a href="haproxy_servers_edit.php"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0"></a></td> + <td valign="middle"><a href="haproxy_pool_edit.php"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0"></a></td> </tr> </table> </td> diff --git a/config/haproxy/haproxy_servers_edit.php b/config/haproxy/haproxy_servers_edit.php deleted file mode 100755 index a4360b04..00000000 --- a/config/haproxy/haproxy_servers_edit.php +++ /dev/null @@ -1,435 +0,0 @@ -<?php -/* $Id: load_balancer_pool_edit.php,v 1.24.2.23 2007/03/03 00:07:09 smos Exp $ */ -/* - haproxy_servers_edit.php - part of pfSense (http://www.pfsense.com/) - Copyright (C) 2009 Scott Ullrich <sullrich@pfsense.com> - Copyright (C) 2008 Remco Hoef <remcoverhoef@pfsense.com> - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - AUTHOR BE LIABLE FOR ANY DIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -require("guiconfig.inc"); - -$d_haproxyconfdirty_path = $g['varrun_path'] . "/haproxy.conf.dirty"; -$a_backend = &$config['installedpackages']['haproxy']['ha_backends']['item']; - -if (!is_array($config['installedpackages']['haproxy']['ha_servers']['item'])) { - $config['installedpackages']['haproxy']['ha_servers']['item'] = array(); -} - -$a_server = &$config['installedpackages']['haproxy']['ha_servers']['item']; - -if (isset($_POST['id'])) - $id = $_POST['id']; -else - $id = $_GET['id']; - -if (isset($id) && $a_server[$id]) { - $pconfig['name'] = $a_server[$id]['name']; - $pconfig['address'] = $a_server[$id]['address']; - $pconfig['port'] = $a_server[$id]['port']; - $pconfig['backend'] = $a_server[$id]['backend']; - $pconfig['weight'] = $a_server[$id]['weight']; - $pconfig['checkinter'] = $a_server[$id]['checkinter']; - $pconfig['cookie'] = $a_server[$id]['cookie']; - $pconfig['status'] = $a_server[$id]['status']; - $pconfig['advanced'] = base64_decode($a_server[$id]['advanced']); -} - -$changedesc = "Services: HAProxy: Servers: "; -$changecount = 0; - -if ($_POST) { - $changecount++; - - unset($input_errors); - $pconfig = $_POST; - - $reqdfields = explode(" ", "name address weight"); - $reqdfieldsn = explode(",", "Name,Address,Weight"); - - do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors); - - if (preg_match("/[^a-zA-Z0-9\.\-_]/", $_POST['name'])) - $input_errors[] = "The field 'Name' contains invalid characters."; - - if (preg_match("/[^a-zA-Z0-9\.]/", $_POST['address'])) - $input_errors[] = "The field 'Address' contains invalid characters."; - - if (preg_match("/[^a-zA-Z0-9\.\-_]/", $_POST['cookie'])) - $input_errors[] = "The field 'Cookie' contains invalid characters."; - - if ($_POST['port'] && !is_numeric($_POST['port'])) - $input_errors[] = "The field 'Port' value is not a number."; - else { - if ($_POST['port']) - if (!($_POST['port']>=1 && $_POST['port']<=65535)) - $input_errors[] = "The field 'Port' value must be between 1 and 65535."; - } - - if (!is_numeric($_POST['weight'])) - $input_errors[] = "The field 'Weight' value is not a number."; - else { - if (!($_POST['weight']>=1 && $_POST['weight']<=256)) - $input_errors[] = "The field 'Weight' value must be between 1 and 256."; - } - - /* Ensure that our pool names are unique */ - for ($i=0; isset($config['installedpackages']['haproxy']['ha_servers']['item'][$i]); $i++) - if (($_POST['name'] == $config['installedpackages']['haproxy']['ha_servers']['item'][$i]['name']) && ($i != $id)) - $input_errors[] = "This server name has already been used. Server names must be unique."; - - $backend = ""; - for($x=0; $x<299; $x++) { - $comd = "\$backends = \$_POST['backend" . $x . "'];"; - eval($comd); - if($backends) - $backend .= "$backends "; - } - $backend = trim($backend); - - if (!$input_errors) { - $server = array(); - if(isset($id) && $a_server[$id]) - $server = $a_server[$id]; - - if($server['name'] != "") - $changedesc .= " modified '{$server['name']}' pool:"; - - update_if_changed("name", $server['name'], $_POST['name']); - update_if_changed("port", $server['port'], $_POST['port']); - update_if_changed("backend", $server['backend'], $backend); - update_if_changed("cookie", $server['cookie'], $_POST['cookie']); - update_if_changed("weight", $server['weight'], $_POST['weight']); - update_if_changed("status", $server['status'], $_POST['status']); - update_if_changed("address", $server['address'], $_POST['address']); - update_if_changed("advanced", $server['advanced'], base64_encode($_POST['advanced'])); - update_if_changed("checkinter", $server['checkinter'], $_POST['checkinter']); - - if (isset($id) && $a_server[$id]) { - $a_server[$id] = $server; - } else { - $a_server[] = $server; - } - - if ($changecount > 0) { - touch($d_haproxyconfdirty_path); - write_config($changedesc); - /* - echo "<PRE>"; - print_r($config); - echo "</PRE>"; - */ - } - - header("Location: haproxy_servers.php"); - exit; - } -} - -$pfSversion = str_replace("\n", "", file_get_contents("/etc/version")); -if(strstr($pfSversion, "1.2")) - $one_two = true; - -$pgtitle = "HAProxy: Server: Edit"; -include("head.inc"); - -row_helper(); - -?> - -<input type='hidden' name='address_type' value='textbox' /> - -<body link="#0000CC" vlink="#0000CC" alink="#0000CC"> -<script type="text/javascript" language="javascript" src="pool.js"></script> - -<script language="javascript"> -function clearcombo(){ - for (var i=document.iform.serversSelect.options.length-1; i>=0; i--){ - document.iform.serversSelect.options[i] = null; - } - document.iform.serversSelect.selectedIndex = -1; -} -</script> -<script type="text/javascript"> - rowname[0] = "backend"; - rowtype[0] = "select"; - rowsize[0] = "1"; -</script> -<?php include("fbegin.inc"); ?> -<?php if ($input_errors) print_input_errors($input_errors); ?> -<?php if($one_two): ?> -<p class="pgtitle"><?=$pgtitle?></p> -<?php endif; ?> - <form action="haproxy_servers_edit.php" method="post" name="iform" id="iform"> - <table width="100%" border="0" cellpadding="6" cellspacing="0"> - <tr> - <td colspan="2" valign="top" class="listtopic">Edit HAProxy server</td> - </tr> - <tr align="left"> - <td width="22%" valign="top" class="vncellreq">Name</td> - <td width="78%" class="vtable" colspan="2"> - <input name="name" type="text" <?if(isset($pconfig['name'])) echo "value=\"{$pconfig['name']}\"";?> size="16" maxlength="16"> - </td> - </tr> - <tr align="left"> - <td width="22%" valign="top" class="vncellreq">Frontend(s)</td> - <td width="78%" class="vtable"> - <table id="frontendtable"> - <tbody> - <tr> - <td><div id="onecolumn"></div></td> - </tr> - <?php - $counter = 0; - $tracker = 0; - $backend = $pconfig['backend']; - $item = explode(" ", $backend); - foreach($item as $ww) { - $address = $ww; - if($counter > 0) - $tracker = $counter + 1; - ?> - <tr> - <td> - <select name="backend<?php echo $tracker; ?>"> - <?php - $i = 0; - if (!is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) - $config['installedpackages']['haproxy']['ha_backends']['item'] = array(); - $backends = split(" ", $pconfig['backend']); - foreach ($a_backend as $backend) { - ?> - <option value="<?=$backend['name'];?>" <?php if($backend['name'] == $ww) echo "SELECTED";?>> - <?=$backend['name'];?> - </option> - <?php } ?> - </select> - </td> - <td> - <?php - if($counter > 0) - echo "<input type=\"image\" src=\"/themes/".$g['theme']."/images/icons/icon_x.gif\" onclick=\"removeRow(this); return false;\" value=\"Delete\" />"; - ?> - </td> - </tr> - <?php - $counter++; - } // end foreach - ?> - </tbody> - <tfoot> - </tfoot> - </table> - <a onclick="javascript:addRowTo('frontendtable'); return false;" href="#"> - <img border="0" src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" alt="" title="add another entry" /> - </a> - </td> - </tr> - <tr> - <td width="22%" valign="top" class="vncellreq"> - <div id="addressnetworkport"> - IP Address - </div> - </td> - <td width="78%" class="vtable"> - <input name="address" type="text" id="address" size="30" value="<?=htmlspecialchars($pconfig['address']);?>" /> - </td> - </tr> - <tr align="left"> - <td width="22%" valign="top" class="vncell">Port</td> - <td width="78%" class="vtable" colspan="2"> - <input name="port" type="text" <?if(isset($pconfig['port'])) echo "value=\"{$pconfig['port']}\"";?> size="5"> - <br/> - NOTE: Leave blank to use Frontend port selection. - </td> - </tr> - <tr align="left"> - <td width="22%" valign="top" class="vncellreq">Status</td> - <td width="78%" class="vtable" colspan="2"> - <select name="status"> - <option value="active" <?php if($pconfig['status']=='active') echo "SELECTED";?>>active</option> - <option value="backup" <?php if($pconfig['status']=='backup') echo "SELECTED";?>>backup</option> - <option value="disabled" <?php if($pconfig['status']=='disabled') echo "SELECTED";?>>disabled</option> - <option value="inactive" <?php if($pconfig['status']=='inactive') echo "SELECTED";?>>inactive</option> - </select> - </td> - </tr> - <tr align="left"> - <td width="22%" valign="top" class="vncell">Cookie</td> - <td width="78%" class="vtable" colspan="2"> - <input name="cookie" type="text" <?if(isset($pconfig['cookie'])) echo "value=\"{$pconfig['cookie']}\"";?>size="64"><br/> - This value will be checked in incoming requests, and the first - operational server possessing the same value will be selected. In return, in - cookie insertion or rewrite modes, this value will be assigned to the cookie - sent to the client. There is nothing wrong in having several servers sharing - the same cookie value, and it is in fact somewhat common between normal and - backup servers. See also the "cookie" keyword in backend section. - - </td> - </tr> - <tr align="left"> - <td width="22%" valign="top" class="vncell">Check inter</td> - <td width="78%" class="vtable" colspan="2"> - <input name="checkinter" type="text" <?if(isset($pconfig['checkinter'])) echo "value=\"{$pconfig['checkinter']}\"";?>size="64"> - <br/>Defaults to 1000 if left blank. - </td> - </tr> - <tr align="left"> - <td width="22%" valign="top" class="vncell">Weight</td> - <td width="78%" class="vtable" colspan="2"> - <input name="weight" type="text" <?if(isset($pconfig['weight'])) echo "value=\"{$pconfig['weight']}\"";?>size="64"><br/> - The default weight is 1, and the maximal value is 255.<br/> - NOTE: If this - parameter is used to distribute the load according to server's capacity, it - is recommended to start with values which can both grow and shrink, for - instance between 10 and 100 to leave enough room above and below for later - adjustments. - </td> - </tr> - <tr align="left"> - <td width="22%" valign="top" class="vncell">Advanced pass thru</td> - <td width="78%" class="vtable" colspan="2"> - <textarea name='advanced' rows="4" cols="70" id='advanced'><?php echo $pconfig['advanced']; ?></textarea> - <br/> - NOTE: paste text into this box that you would like to pass thru. - </td> - </tr> - <tr align="left"> - <td width="22%" valign="top"> </td> - <td width="78%"> - <input name="Submit" type="submit" class="formbtn" value="Save"> - <input type="button" class="formbtn" value="Cancel" onclick="history.back()"> - <?php if (isset($id) && $a_server[$id]): ?> - <input name="id" type="hidden" value="<?=$id;?>"> - <?php endif; ?> - </td> - </tr> - </table> - </form> -<br> -<?php include("fend.inc"); ?> -<script type="text/javascript"> - field_counter_js = 1; - rows = 1; - totalrows = <?php echo $counter; ?>; - loaded = <?php echo $counter; ?>; -</script> -</body> -</html> - -<?php - -function row_helper() { - global $pconfig, $a_backend; - $options = ""; - if($a_backend) { - foreach ($a_backend as $backend) { - $options .= "<option value='{$backend['name']}'"; - if($backend['name'] == $pconfig['backend']) - $options .= "SELECTED"; - $options .= ">"; - $options .= $backend['name']; - $options .= "</option>"; - } - } - - echo <<<EOF -<script type="text/javascript"> -// Global Variables -var rowname = new Array(99); -var rowtype = new Array(99); -var newrow = new Array(99); -var rowsize = new Array(99); - -for (i = 0; i < 99; i++) { - rowname[i] = ''; - rowtype[i] = ''; - newrow[i] = ''; - rowsize[i] = '25'; -} - -var field_counter_js = 0; -var loaded = 0; -var is_streaming_progress_bar = 0; -var temp_streaming_text = ""; - -var addRowTo = (function() { - return (function (tableId) { - var d, tbody, tr, td, bgc, i, ii, j; - d = document; - tbody = d.getElementById(tableId).getElementsByTagName("tbody").item(0); - tr = d.createElement("tr"); - totalrows++; - for (i = 0; i < field_counter_js; i++) { - td = d.createElement("td"); - if(rowtype[i] == 'textbox') { - td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + "'></input><input size='" + rowsize[i] + "' name='" + rowname[i] + totalrows + "'></input> "; - } else if(rowtype[i] == 'select') { - td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + "'></input><select size='" + rowsize[i] + "' name='" + rowname[i] + totalrows + "'>$options</select> "; - } else { - td.innerHTML="<INPUT type='hidden' value='" + totalrows +"' name='" + rowname[i] + "_row-" + totalrows + "'></input><input type='checkbox' name='" + rowname[i] + totalrows + "'></input> "; - } - tr.appendChild(td); - } - td = d.createElement("td"); - td.rowSpan = "1"; - - td.innerHTML = '<input type="image" src="/themes/' + theme + '/images/icons/icon_x.gif" onclick="removeRow(this); return false;" value="Delete">'; - tr.appendChild(td); - tbody.appendChild(tr); - }); -})(); - -function removeRow(el) { - var cel; - while (el && el.nodeName.toLowerCase() != "tr") - el = el.parentNode; - - if (el && el.parentNode) { - cel = el.getElementsByTagName("td").item(0); - el.parentNode.removeChild(el); - } -} - -function find_unique_field_name(field_name) { - // loop through field_name and strip off -NUMBER - var last_found_dash = 0; - for (var i = 0; i < field_name.length; i++) { - // is this a dash, if so, update - // last_found_dash - if (field_name.substr(i,1) == "-" ) - last_found_dash = i; - } - if (last_found_dash < 1) - return field_name; - return(field_name.substr(0,last_found_dash)); -} -</script> - -EOF; - -} - -?>
\ No newline at end of file |