Merge "Scenario tests: improve test http server"
This commit is contained in:
commit
451faa2534
1
devstack/files/debs/octavia
Normal file
1
devstack/files/debs/octavia
Normal file
@ -0,0 +1 @@
|
|||||||
|
golang
|
1
devstack/files/rpms/octavia
Normal file
1
devstack/files/rpms/octavia
Normal file
@ -0,0 +1 @@
|
|||||||
|
golang
|
87
octavia/tests/contrib/httpd.go
Normal file
87
octavia/tests/contrib/httpd.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sess_cookie http.Cookie
|
||||||
|
var resp string
|
||||||
|
|
||||||
|
type ConnectionCount struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
cur_conn int
|
||||||
|
max_conn int
|
||||||
|
total_conn int
|
||||||
|
}
|
||||||
|
|
||||||
|
var scoreboard ConnectionCount
|
||||||
|
|
||||||
|
func (cc *ConnectionCount) open() {
|
||||||
|
cc.mu.Lock()
|
||||||
|
defer cc.mu.Unlock()
|
||||||
|
|
||||||
|
cc.cur_conn++
|
||||||
|
cc.total_conn++
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cc *ConnectionCount) close() {
|
||||||
|
cc.mu.Lock()
|
||||||
|
defer cc.mu.Unlock()
|
||||||
|
|
||||||
|
if cc.cur_conn > cc.max_conn {
|
||||||
|
cc.max_conn = cc.cur_conn
|
||||||
|
}
|
||||||
|
cc.cur_conn--
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cc *ConnectionCount) stats() (int, int) {
|
||||||
|
cc.mu.Lock()
|
||||||
|
defer cc.mu.Unlock()
|
||||||
|
|
||||||
|
return cc.max_conn, cc.total_conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func root_handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
scoreboard.open()
|
||||||
|
defer scoreboard.close()
|
||||||
|
|
||||||
|
http.SetCookie(w, &sess_cookie)
|
||||||
|
io.WriteString(w, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func slow_handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
scoreboard.open()
|
||||||
|
defer scoreboard.close()
|
||||||
|
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
http.SetCookie(w, &sess_cookie)
|
||||||
|
io.WriteString(w, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func stats_handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
http.SetCookie(w, &sess_cookie)
|
||||||
|
max_conn, total_conn := scoreboard.stats()
|
||||||
|
fmt.Fprintf(w, "max_conn=%d\ntotal_conn=%d\n", max_conn, total_conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
portPtr := flag.Int("port", 8080, "TCP port to listen on")
|
||||||
|
idPtr := flag.Int("id", 1, "Server ID")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
resp = fmt.Sprintf("server%d", *idPtr)
|
||||||
|
sess_cookie.Name = "JESSIONID"
|
||||||
|
sess_cookie.Value = fmt.Sprintf("%d", *idPtr)
|
||||||
|
|
||||||
|
http.HandleFunc("/", root_handler)
|
||||||
|
http.HandleFunc("/slow", slow_handler)
|
||||||
|
http.HandleFunc("/stats", stats_handler)
|
||||||
|
portStr := fmt.Sprintf(":%d", *portPtr)
|
||||||
|
http.ListenAndServe(portStr, nil)
|
||||||
|
}
|
@ -17,7 +17,9 @@ try:
|
|||||||
from http import cookiejar as cookielib
|
from http import cookiejar as cookielib
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import cookielib
|
import cookielib
|
||||||
|
import os
|
||||||
import shlex
|
import shlex
|
||||||
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
@ -47,6 +49,9 @@ from octavia.tests.tempest.v1.clients import pools_client
|
|||||||
config = config.CONF
|
config = config.CONF
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
HTTPD_SRC = os.path.abspath(
|
||||||
|
os.path.join(os.path.dirname(__file__),
|
||||||
|
'../../../contrib/httpd.go'))
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(manager.NetworkScenarioTest):
|
class BaseTestCase(manager.NetworkScenarioTest):
|
||||||
@ -221,6 +226,18 @@ class BaseTestCase(manager.NetworkScenarioTest):
|
|||||||
waiters.wait_for_server_status(self.servers_client,
|
waiters.wait_for_server_status(self.servers_client,
|
||||||
value, 'ACTIVE')
|
value, 'ACTIVE')
|
||||||
|
|
||||||
|
def _build_static_httpd(self):
|
||||||
|
"""Compile test httpd as a static binary
|
||||||
|
|
||||||
|
returns file path of resulting binary file
|
||||||
|
"""
|
||||||
|
builddir = tempfile.mkdtemp()
|
||||||
|
shutil.copyfile(HTTPD_SRC, os.path.join(builddir, 'httpd.go'))
|
||||||
|
self.execute('go build -ldflags '
|
||||||
|
'"-linkmode external -extldflags -static" '
|
||||||
|
'httpd.go', cwd=builddir)
|
||||||
|
return os.path.join(builddir, 'httpd')
|
||||||
|
|
||||||
def _start_servers(self):
|
def _start_servers(self):
|
||||||
"""Start one or more backends
|
"""Start one or more backends
|
||||||
|
|
||||||
@ -236,46 +253,30 @@ class BaseTestCase(manager.NetworkScenarioTest):
|
|||||||
ip_address=ip,
|
ip_address=ip,
|
||||||
private_key=private_key)
|
private_key=private_key)
|
||||||
|
|
||||||
# Write a backend's response into a file
|
httpd = self._build_static_httpd()
|
||||||
resp = ('echo -ne "HTTP/1.1 200 OK\r\nContent-Length: 7\r\n'
|
|
||||||
'Set-Cookie:JSESSIONID=%(s_id)s\r\nConnection: close\r\n'
|
|
||||||
'Content-Type: text/html; '
|
|
||||||
'charset=UTF-8\r\n\r\n%(server)s"; cat >/dev/null')
|
|
||||||
|
|
||||||
with tempfile.NamedTemporaryFile() as script:
|
with tempfile.NamedTemporaryFile() as key:
|
||||||
script.write(resp % {'s_id': server_name[-1],
|
key.write(private_key)
|
||||||
'server': server_name})
|
key.flush()
|
||||||
script.flush()
|
self.copy_file_to_host(httpd,
|
||||||
with tempfile.NamedTemporaryFile() as key:
|
"/dev/shm/httpd",
|
||||||
key.write(private_key)
|
ip,
|
||||||
key.flush()
|
username, key.name)
|
||||||
self.copy_file_to_host(script.name,
|
|
||||||
"/tmp/script1",
|
|
||||||
ip,
|
|
||||||
username, key.name)
|
|
||||||
|
|
||||||
# Start netcat
|
# Start httpd
|
||||||
start_server = ('while true; do '
|
start_server = ('sudo sh -c "ulimit -n 100000; nohup '
|
||||||
'sudo nc -ll -p %(port)s -e sh /tmp/%(script)s; '
|
'/dev/shm/httpd -id %(id)s '
|
||||||
'done > /dev/null &')
|
'-port %(port)s &"')
|
||||||
cmd = start_server % {'port': self.port1,
|
cmd = start_server % {'id': server_name[-1],
|
||||||
'script': 'script1'}
|
'port': self.port1}
|
||||||
ssh_client.exec_command(cmd)
|
ssh_client.exec_command(cmd)
|
||||||
|
|
||||||
|
# In single server case run a second server on an alternate port
|
||||||
if len(self.server_ips) == 1:
|
if len(self.server_ips) == 1:
|
||||||
with tempfile.NamedTemporaryFile() as script:
|
cmd = start_server % {'id': '2',
|
||||||
script.write(resp % {'s_id': 2,
|
'port': self.port2}
|
||||||
'server': 'server2'})
|
|
||||||
script.flush()
|
|
||||||
with tempfile.NamedTemporaryFile() as key:
|
|
||||||
key.write(private_key)
|
|
||||||
key.flush()
|
|
||||||
self.copy_file_to_host(script.name,
|
|
||||||
"/tmp/script2", ip,
|
|
||||||
username, key.name)
|
|
||||||
cmd = start_server % {'port': self.port2,
|
|
||||||
'script': 'script2'}
|
|
||||||
ssh_client.exec_command(cmd)
|
ssh_client.exec_command(cmd)
|
||||||
|
# Allow ssh_client connection to fall out of scope
|
||||||
|
|
||||||
def _create_listener(self, load_balancer_id, default_pool_id=None):
|
def _create_listener(self, load_balancer_id, default_pool_id=None):
|
||||||
"""Create a listener with HTTP protocol listening on port 80."""
|
"""Create a listener with HTTP protocol listening on port 80."""
|
||||||
@ -754,9 +755,13 @@ class BaseTestCase(manager.NetworkScenarioTest):
|
|||||||
"-i %(pkey)s %(file1)s %(dest)s" % {'pkey': pkey,
|
"-i %(pkey)s %(file1)s %(dest)s" % {'pkey': pkey,
|
||||||
'file1': file_from,
|
'file1': file_from,
|
||||||
'dest': dest})
|
'dest': dest})
|
||||||
|
return self.execute(cmd)
|
||||||
|
|
||||||
|
def execute(self, cmd, cwd=None):
|
||||||
args = shlex.split(cmd.encode('utf-8'))
|
args = shlex.split(cmd.encode('utf-8'))
|
||||||
subprocess_args = {'stdout': subprocess.PIPE,
|
subprocess_args = {'stdout': subprocess.PIPE,
|
||||||
'stderr': subprocess.STDOUT}
|
'stderr': subprocess.STDOUT,
|
||||||
|
'cwd': cwd}
|
||||||
proc = subprocess.Popen(args, **subprocess_args)
|
proc = subprocess.Popen(args, **subprocess_args)
|
||||||
stdout, stderr = proc.communicate()
|
stdout, stderr = proc.communicate()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
|
Loading…
Reference in New Issue
Block a user