Merge "Define and use octavia nodesets"
diff --git a/octavia_tempest_plugin/contrib/test_server/README.rst b/octavia_tempest_plugin/contrib/test_server/README.rst
index da719b7..ba959f9 100644
--- a/octavia_tempest_plugin/contrib/test_server/README.rst
+++ b/octavia_tempest_plugin/contrib/test_server/README.rst
@@ -2,8 +2,8 @@
 Amphorae test server
 ====================
 
-test_server is a static application that simulates an HTTP and a UDP server.
-
+test_server.bin is a static application that simulates HTTP, HTTPS, and UDP
+servers. This server can properly handle concurrent requests.
 
 Building
 --------
@@ -12,15 +12,55 @@
 
 Install dependencies for Ubuntu/Debian:
 
+::
+
     sudo apt-get install -y golang
 
 Install dependencies for Centos (use golang 1.10 from go-toolset-7) and launch
 a shell into the new environment:
 
+::
+
     sudo yum install -y centos-release-scl
     sudo yum install -y go-toolset-7-golang-bin glibc-static openssl-static zlib-static
     scl enable go-toolset-7 bash
 
 Build the binary:
 
+::
+
     CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-s -w -extldflags -static' -o test_server.bin test_server.go
+
+
+Usage
+-----
+
+The usage string can be output from the command by running:
+
+::
+
+    ./test_server.bin --help
+
+Example output:
+
+::
+
+  Usage of ./test_server.bin:
+    -cert string
+          Server side PEM format certificate.
+    -client_ca string
+          Client side PEM format CA certificate.
+    -https_port int
+          HTTPS port to listen on, -1 is disabled. (default -1)
+    -id string
+          Server ID (default "1")
+    -key string
+          Server side PEM format key.
+    -port int
+          Port to listen on (default 8080)
+
+If -https_port is not specified, the server will not accept HTTPS requests.
+When --https_port is specified, -cert and -key are required parameters.
+If -https_port is specified, the -client_ca parameter is optional. When
+-client_ca is specified, it will configure the HTTPS port to require a valid
+client certificate to connect.
diff --git a/octavia_tempest_plugin/contrib/test_server/test_server.bin b/octavia_tempest_plugin/contrib/test_server/test_server.bin
index e3cc7ba..75ec2f2 100755
--- a/octavia_tempest_plugin/contrib/test_server/test_server.bin
+++ b/octavia_tempest_plugin/contrib/test_server/test_server.bin
Binary files differ
diff --git a/octavia_tempest_plugin/contrib/test_server/test_server.go b/octavia_tempest_plugin/contrib/test_server/test_server.go
index 8139580..f8bc1e0 100644
--- a/octavia_tempest_plugin/contrib/test_server/test_server.go
+++ b/octavia_tempest_plugin/contrib/test_server/test_server.go
@@ -1,11 +1,17 @@
 package main
 
 import (
+	"crypto/rand"
+	"crypto/tls"
+	"crypto/x509"
 	"flag"
 	"fmt"
 	"io"
+	"io/ioutil"
+	"log"
 	"net"
 	"net/http"
+	"os"
 	"sync"
 	"time"
 )
@@ -83,13 +89,23 @@
 	fmt.Fprintf(w, "max_conn=%d\ntotal_conn=%d\n", max_conn, total_conn)
 }
 
+func https_wrapper(base_handler func(http.ResponseWriter,
+	*http.Request)) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+
+		w.Header().Add("Strict-Transport-Security",
+			"max-age=66012000; includeSubDomains")
+		base_handler(w, r)
+	})
+}
+
 func reset_handler(w http.ResponseWriter, r *http.Request) {
 	http.SetCookie(w, &sess_cookie)
 	scoreboard.reset()
 	fmt.Fprintf(w, "reset\n")
 }
 
-func http_serve(port int, id string) {
+func http_setup(id string) {
 	sess_cookie.Name = "JSESSIONID"
 	sess_cookie.Value = id
 
@@ -97,8 +113,65 @@
 	http.HandleFunc("/slow", slow_handler)
 	http.HandleFunc("/stats", stats_handler)
 	http.HandleFunc("/reset", reset_handler)
+}
+
+func http_serve(port int, id string) {
 	portStr := fmt.Sprintf(":%d", port)
-	http.ListenAndServe(portStr, nil)
+	log.Fatal(http.ListenAndServe(portStr, nil))
+}
+
+func https_serve(port int, id string, cert tls.Certificate,
+	certpool *x509.CertPool, server_cert_pem string,
+	server_key_pem string) {
+	mux := http.NewServeMux()
+	mux.Handle("/", https_wrapper(root_handler))
+	mux.Handle("/slow", https_wrapper(slow_handler))
+	mux.Handle("/stats", https_wrapper(stats_handler))
+	mux.Handle("/reset", https_wrapper(reset_handler))
+
+	var tls_config *tls.Config
+	if certpool != nil {
+		tls_config = &tls.Config{
+			Certificates: []tls.Certificate{cert},
+			ClientAuth:   tls.RequireAndVerifyClientCert,
+			ClientCAs:    certpool,
+			MinVersion:   tls.VersionTLS12,
+			CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384,
+				tls.CurveP256},
+			PreferServerCipherSuites: true,
+			CipherSuites: []uint16{
+				tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+				tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+				tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
+				tls.TLS_RSA_WITH_AES_256_CBC_SHA,
+			},
+		}
+	} else {
+		tls_config = &tls.Config{
+			Certificates: []tls.Certificate{cert},
+			ClientAuth:   tls.NoClientCert,
+			MinVersion:   tls.VersionTLS12,
+			CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384,
+				tls.CurveP256},
+			PreferServerCipherSuites: true,
+			CipherSuites: []uint16{
+				tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+				tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+				tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
+				tls.TLS_RSA_WITH_AES_256_CBC_SHA,
+			},
+		}
+	}
+	tls_config.Rand = rand.Reader
+	portStr := fmt.Sprintf(":%d", port)
+	srv := &http.Server{
+		Addr:      portStr,
+		Handler:   mux,
+		TLSConfig: tls_config,
+		TLSNextProto: make(map[string]func(*http.Server, *tls.Conn,
+			http.Handler), 0),
+	}
+	log.Fatal(srv.ListenAndServeTLS(server_cert_pem, server_key_pem))
 }
 
 func udp_serve(port int, id string) {
@@ -129,11 +202,44 @@
 func main() {
 	portPtr := flag.Int("port", 8080, "Port to listen on")
 	idPtr := flag.String("id", "1", "Server ID")
+	https_portPtr := flag.Int("https_port", -1,
+		"HTTPS port to listen on, -1 is disabled.")
+	server_cert_pem := flag.String("cert", "",
+		"Server side PEM format certificate.")
+	server_key := flag.String("key", "", "Server side PEM format key.")
+	client_ca_cert_pem := flag.String("client_ca", "",
+		"Client side PEM format CA certificate.")
 
 	flag.Parse()
 
 	resp = fmt.Sprintf("%s", *idPtr)
 
+	http_setup(*idPtr)
+
+	if *https_portPtr > -1 {
+		cert, err := tls.LoadX509KeyPair(*server_cert_pem, *server_key)
+		if err != nil {
+			fmt.Println("Error load server certificate and key.\n")
+			os.Exit(1)
+		}
+		certpool := x509.NewCertPool()
+		if *client_ca_cert_pem != "" {
+			ca_pem, err := ioutil.ReadFile(*client_ca_cert_pem)
+			if err != nil {
+				fmt.Println("Error load client side CA cert.\n")
+				os.Exit(1)
+			}
+			if !certpool.AppendCertsFromPEM(ca_pem) {
+				fmt.Println("Can't parse client side certificate authority")
+				os.Exit(1)
+			}
+		} else {
+			certpool = nil
+		}
+		go https_serve(*https_portPtr, *idPtr, cert, certpool,
+			*server_cert_pem, *server_key)
+	}
+
 	go http_serve(*portPtr, *idPtr)
 	udp_serve(*portPtr, *idPtr)
 }
diff --git a/setup.cfg b/setup.cfg
index 3e5d216..d7d3196 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -19,6 +19,7 @@
     Programming Language :: Python :: 3
     Programming Language :: Python :: 3.6
     Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3.8
 
 [global]
 setup-hooks =
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
index 4b04fe9..239eb49 100644
--- a/zuul.d/jobs.yaml
+++ b/zuul.d/jobs.yaml
@@ -341,6 +341,7 @@
           g-api: true
           g-reg: true
           key: true
+          memory_tracker: false
           mysql: true
           n-api: true
           n-api-meta: true
@@ -356,7 +357,6 @@
           o-cw: true
           o-hm: true
           o-hk: true
-          peakmem_tracker: true
           placement-api: true
           q-agt: true
           q-dhcp: true