├── .gitignore ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── latency.go └── terraform ├── .gitignore ├── README.md ├── bootstrap ├── install.sh ├── run_server.sh └── setenv.sh ├── client ├── ca.pem ├── client-key.pem ├── client.pem └── run_tests.sh ├── gcp ├── README.md ├── main.tf ├── output.tf └── variables.tf ├── packet ├── README.md ├── main.tf ├── output.tf └── variables.tf ├── servera ├── ca.pem ├── gnatsd.conf ├── servera-key.pem └── servera.pem ├── serverb ├── ca.pem ├── gnatsd.conf ├── serverb-key.pem └── serverb.pem └── tls-scripts ├── config ├── ca-config.json ├── ca-csr.json ├── client.json ├── servera.json └── serverb.json └── gencerts.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | latency-tests 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NATS Latency and Throughput Test Framework 2 | 3 | ### Install 4 | ``` 5 | go get github.com/nats-io/latency-tests 6 | ``` 7 | 8 | ### Running a local NATS server. 9 | 10 | You do not need a local server to run the test framework. However if you want to do so, the recommended way to install the NATS server is to [download](http://nats.io/download/) one of the pre-built release binaries which are available for OSX, Linux (x86-64/ARM), Windows, and Docker. Instructions for using these binaries are on the [GitHub releases page][github-release]. 11 | 12 | 13 | [github-release]: https://github.com/nats-io/gnatsd/releases/ 14 | 15 | ### Running a test. 16 | 17 | ``` 18 | > go build latency.go 19 | > ./latency -h 20 | 21 | Usage: latency-tests [options] 22 | 23 | Test Options: 24 | -sa ServerA (Publish) (default: nats://localhost:4222) 25 | -sb ServerB (Subscribe) (default: nats://localhost:4222) 26 | -sz Message size in bytes (default: 8) 27 | -tr Rate in msgs/sec (default: 1000) 28 | -tt Test duration (default: 5s) 29 | -hist Histogram output file 30 | -secure Enable TLS without verfication (default: false) 31 | -tls_ca TLS Certificate CA file 32 | -tls_key TLS Private Key 33 | -tls_cert TLS Certificate 34 | 35 | ``` 36 | 37 | The test framework will run a test to publish and subscribe to messages. Publish operations will happen on one connection to ServerA, and Subscriptions will be on another connection to ServerB. ServerA and ServerB can be the same server. 38 | 39 | You are able to specify various options such as message size [-sz], transmit rate [-tr], test time duration [-tt], and output file for plotting with http://hdrhistogram.github.io/HdrHistogram/plotFiles.html. 40 | 41 | ### Example 42 | 43 | ``` 44 | > ./latency -sa tls://demo.nats.io:4443 -sb tls://demo.nats.io:4443 -tr 1000 -tt 5s -sz 512 45 | ``` 46 | 47 | This example will connect both connections to a secure demo server, attempting to send at 1000 msgs/sec with each message payload being 512 bytes long. This test duration will be ~5 seconds. 48 | 49 | ### Output 50 | 51 | ```text 52 | ============================== 53 | Pub Server RTT : 1.65ms 54 | Sub Server RTT : 2.817ms 55 | Message Payload: 512B 56 | Target Duration: 5s 57 | Target Msgs/Sec: 1000 58 | Target Band/Sec: 1000K 59 | ============================== 60 | HDR Percentiles: 61 | 10: 1.998ms 62 | 50: 2.058ms 63 | 75: 2.095ms 64 | 90: 2.132ms 65 | 99: 2.271ms 66 | 99.99: 3.106ms 67 | 99.999: 3.126ms 68 | 99.9999: 3.126ms 69 | 99.99999: 3.126ms 70 | 100: 3.126ms 71 | ============================== 72 | Actual Msgs/Sec: 998 73 | Actual Band/Sec: 998K 74 | Minimum Latency: 1.919ms 75 | Median Latency : 2.058ms 76 | Maximum Latency: 3.126ms 77 | 1st Sent Wall Time : 153.489ms 78 | Last Sent Wall Time: 5.005243s 79 | Last Recv Wall Time: 5.006857s 80 | ``` 81 | 82 | This is output from the previous example run. The test framework will establish a rough estimate of the RTT to each server via a call to ``nats.Flush()``. The message payload size, test duration and target msgs/sec and subsequent bandwidth will be noted. After the test completes the histogram percentiles for 10th, 50th, 75th, 90th, 99th, 99.99th, 99.999th, 99.9999th, 99.99999th, and 100th percentiles are printed. After this, we print the actual results of achieved msgs/sec, bandwidth/sec, the minimum, median, and maximum latencies, and wall times recorded in the test run. Note that the number of measurements (total messages) may cause overlap in the highest percential latency measurements, as demonstrated in the output above with 5000 measurements. 83 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/nats-io/latency-tests 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd 7 | github.com/nats-io/nats.go v1.10.0 8 | github.com/tylertreat/hdrhistogram-writer v0.0.0-20180430173243-73b8d31ba571 9 | ) 10 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= 2 | github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= 3 | github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI= 4 | github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= 5 | github.com/nats-io/nats.go v1.10.0 h1:L8qnKaofSfNFbXg0C5F71LdjPRnmQwSsA4ukmkt1TvY= 6 | github.com/nats-io/nats.go v1.10.0/go.mod h1:AjGArbfyR50+afOUotNX2Xs5SYHf+CoOa5HH1eEl2HE= 7 | github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= 8 | github.com/nats-io/nkeys v0.1.4 h1:aEsHIssIk6ETN5m2/MD8Y4B2X7FfXrBAUdkyRvbVYzA= 9 | github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= 10 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= 11 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 12 | github.com/tylertreat/hdrhistogram-writer v0.0.0-20180430173243-73b8d31ba571 h1:y3jfVjUvgUFkVdIbdxDTwGx7RxKYzFVJgs+0csOZRmk= 13 | github.com/tylertreat/hdrhistogram-writer v0.0.0-20180430173243-73b8d31ba571/go.mod h1:4S/OyneYS8uVUnbaUwp3TCt3oIVNq+BXENCkC649sFk= 14 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 15 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 16 | golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM= 17 | golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 18 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 19 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 20 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 21 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 22 | -------------------------------------------------------------------------------- /latency.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/binary" 6 | "flag" 7 | "fmt" 8 | "io" 9 | "log" 10 | "math" 11 | "os" 12 | "runtime/debug" 13 | "sort" 14 | "strings" 15 | "sync" 16 | "sync/atomic" 17 | "time" 18 | 19 | "github.com/codahale/hdrhistogram" 20 | "github.com/nats-io/nats.go" 21 | hw "github.com/tylertreat/hdrhistogram-writer" 22 | ) 23 | 24 | // Test Parameters 25 | var ( 26 | ServerA string 27 | ServerB string 28 | TargetPubRate int 29 | MsgSize int 30 | NumPubs int 31 | TestDuration time.Duration 32 | HistFile string 33 | Secure bool 34 | TLSca string 35 | TLSkey string 36 | TLScert string 37 | UserCreds string 38 | ) 39 | 40 | var usageStr = ` 41 | Usage: latency-tests [options] 42 | 43 | Test Options: 44 | -sa ServerA (Publish) (default: nats://localhost:4222) 45 | -sb ServerB (Subscribe) (default: nats://localhost:4222) 46 | -sz Message size in bytes (default: 8) 47 | -tr Rate in msgs/sec (default: 1000) 48 | -tt Test duration (default: 5s) 49 | -hist Histogram output file 50 | -secure Enable TLS without verfication (default: false) 51 | -tls_ca TLS Certificate CA file 52 | -tls_key TLS Private Key 53 | -tls_cert TLS Certificate 54 | -creds User Credentials 55 | ` 56 | 57 | func usage() { 58 | log.Fatalf(usageStr + "\n") 59 | } 60 | 61 | // waitForRoute tests a subscription in the server to ensure subject interest 62 | // has been propagated between servers. Otherwise, we may miss early messages 63 | // when testing with clustered servers and the test will hang. 64 | func waitForRoute(pnc, snc *nats.Conn) { 65 | 66 | // No need to continue if using one server 67 | if strings.Compare(pnc.ConnectedServerId(), snc.ConnectedServerId()) == 0 { 68 | return 69 | } 70 | 71 | // Setup a test subscription to let us know when a message has been received. 72 | // Use a new inbox subject as to not skew results 73 | var routed int32 74 | subject := nats.NewInbox() 75 | sub, err := snc.Subscribe(subject, func(msg *nats.Msg) { 76 | atomic.AddInt32(&routed, 1) 77 | }) 78 | if err != nil { 79 | log.Fatalf("Couldn't subscribe to test subject %s: %v", subject, err) 80 | } 81 | defer sub.Unsubscribe() 82 | snc.Flush() 83 | 84 | // Periodically send messages until the test subscription receives 85 | // a message. Allow for two seconds. 86 | start := time.Now() 87 | for atomic.LoadInt32(&routed) == 0 { 88 | if time.Since(start) > (time.Second * 2) { 89 | log.Fatalf("Couldn't receive end-to-end test message.") 90 | } 91 | if err = pnc.Publish(subject, nil); err != nil { 92 | log.Fatalf("Couldn't publish to test subject %s: %v", subject, err) 93 | } 94 | time.Sleep(10 * time.Millisecond) 95 | } 96 | } 97 | 98 | func main() { 99 | start := time.Now() 100 | 101 | flag.StringVar(&ServerA, "sa", nats.DefaultURL, "ServerA - Publisher") 102 | flag.StringVar(&ServerB, "sb", nats.DefaultURL, "ServerB - Subscriber") 103 | flag.IntVar(&TargetPubRate, "tr", 1000, "Target Publish Rate") 104 | flag.IntVar(&MsgSize, "sz", 8, "Message Payload Size") 105 | flag.DurationVar(&TestDuration, "tt", 5*time.Second, "Target Test Time") 106 | flag.StringVar(&HistFile, "hist", "", "Histogram and Raw Output") 107 | flag.BoolVar(&Secure, "secure", false, "Use a TLS Connection w/o verification") 108 | flag.StringVar(&TLSkey, "tls_key", "", "Private key file") 109 | flag.StringVar(&TLScert, "tls_cert", "", "Certificate file") 110 | flag.StringVar(&TLSca, "tls_ca", "", "Certificate CA file") 111 | flag.StringVar(&UserCreds, "creds", "", "User Credentials File") 112 | 113 | log.SetFlags(0) 114 | flag.Usage = usage 115 | flag.Parse() 116 | 117 | // Slow down GC. 118 | debug.SetGCPercent(500) 119 | 120 | NumPubs = int(TestDuration/time.Second) * TargetPubRate 121 | 122 | if MsgSize < 8 { 123 | log.Fatalf("Message Payload Size must be at least %d bytes\n", 8) 124 | } 125 | 126 | // Setup connection options 127 | var opts []nats.Option 128 | if Secure { 129 | opts = append(opts, nats.Secure()) 130 | } 131 | if TLSca != "" { 132 | opts = append(opts, nats.RootCAs(TLSca)) 133 | } 134 | if TLScert != "" { 135 | opts = append(opts, nats.ClientCert(TLScert, TLSkey)) 136 | } 137 | if UserCreds != "" { 138 | opts = append(opts, nats.UserCredentials(UserCreds)) 139 | } 140 | 141 | c1, err := nats.Connect(ServerA, opts...) 142 | if err != nil { 143 | log.Fatalf("Could not connect to ServerA: %v", err) 144 | } 145 | defer c1.Close() 146 | 147 | c2, err := nats.Connect(ServerB, opts...) 148 | if err != nil { 149 | log.Fatalf("Could not connect to ServerB: %v", err) 150 | } 151 | defer c2.Close() 152 | 153 | // Do some quick RTT calculations 154 | log.Println("==============================") 155 | now := time.Now() 156 | c1.Flush() 157 | log.Printf("Pub Server RTT : %v\n", fmtDur(time.Since(now))) 158 | 159 | now = time.Now() 160 | c2.Flush() 161 | log.Printf("Sub Server RTT : %v\n", fmtDur(time.Since(now))) 162 | 163 | // Duration tracking 164 | durations := make([]time.Duration, 0, NumPubs) 165 | 166 | // Wait for all messages to be received. 167 | var wg sync.WaitGroup 168 | wg.Add(1) 169 | 170 | //Random subject (to run multiple tests in parallel) 171 | subject := nats.NewInbox() 172 | 173 | // Count the messages. 174 | received := 0 175 | 176 | // Async Subscriber (Runs in its own Goroutine) 177 | c2.Subscribe(subject, func(msg *nats.Msg) { 178 | sendTime := int64(binary.LittleEndian.Uint64(msg.Data)) 179 | durations = append(durations, time.Duration(time.Now().UnixNano()-sendTime)) 180 | received++ 181 | if received >= NumPubs { 182 | wg.Done() 183 | } 184 | }) 185 | // Make sure interest is set for subscribe before publish since a different connection. 186 | c2.Flush() 187 | 188 | // wait for routes to be established so we get every message 189 | waitForRoute(c1, c2) 190 | 191 | log.Printf("Message Payload: %v\n", byteSize(MsgSize)) 192 | log.Printf("Target Duration: %v\n", TestDuration) 193 | log.Printf("Target Msgs/Sec: %v\n", TargetPubRate) 194 | log.Printf("Target Band/Sec: %v\n", bps(TargetPubRate*MsgSize*2)) 195 | log.Println("==============================") 196 | 197 | // Random payload 198 | data := make([]byte, MsgSize) 199 | io.ReadFull(rand.Reader, data) 200 | 201 | // For publish throttling 202 | delay := time.Second / time.Duration(TargetPubRate) 203 | pubStart := time.Now() 204 | 205 | // Throttle logic, crude I know, but works better then time.Ticker or 206 | // golang.org/x/time/rate. 207 | 208 | adjustAndSleep := func(now time.Time, count int) { 209 | r := rps(count, now.Sub(pubStart)) 210 | adj := delay/20 + time.Nanosecond // 5% 211 | if r < TargetPubRate { 212 | delay -= adj 213 | if delay < 0 { 214 | delay = 0 215 | } 216 | } else if r > TargetPubRate { 217 | delay += adj 218 | } 219 | if delay > 0 { 220 | time.Sleep(delay) 221 | } 222 | } 223 | 224 | // Now publish 225 | for i := 0; i < NumPubs; i++ { 226 | now := time.Now() 227 | // Place the send time in the front of the payload. 228 | binary.LittleEndian.PutUint64(data[0:], uint64(now.UnixNano())) 229 | c1.Publish(subject, data) 230 | adjustAndSleep(now, i+1) 231 | } 232 | pubDur := time.Since(pubStart) 233 | wg.Wait() 234 | subDur := time.Since(pubStart) 235 | 236 | // If we are writing to files, save the original unsorted data 237 | if HistFile != "" { 238 | if err := writeRawFile(HistFile+".raw", durations); err != nil { 239 | log.Printf("Unable to write raw output file: %v", err) 240 | } 241 | } 242 | 243 | sort.Slice(durations, func(i, j int) bool { return durations[i] < durations[j] }) 244 | 245 | h := hdrhistogram.New(1, int64(durations[len(durations)-1]), 5) 246 | for _, d := range durations { 247 | h.RecordValue(int64(d)) 248 | } 249 | 250 | log.Printf("HDR Percentiles:\n") 251 | log.Printf("10: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(10)))) 252 | log.Printf("50: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(50)))) 253 | log.Printf("75: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(75)))) 254 | log.Printf("90: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(90)))) 255 | log.Printf("99: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(99)))) 256 | log.Printf("99.9: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(99.9)))) 257 | log.Printf("99.99: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(99.99)))) 258 | log.Printf("99.999: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(99.999)))) 259 | log.Printf("99.9999: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(99.9999)))) 260 | log.Printf("99.99999: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(99.99999)))) 261 | log.Printf("100: %v\n", fmtDur(time.Duration(h.ValueAtQuantile(100.0)))) 262 | log.Println("==============================") 263 | 264 | if HistFile != "" { 265 | pctls := hw.Percentiles{10, 25, 50, 75, 90, 99, 99.9, 99.99, 99.999, 99.9999, 99.99999, 100.0} 266 | hw.WriteDistributionFile(h, pctls, 1.0/1000000.0, HistFile+".histogram") 267 | } 268 | 269 | // Print results 270 | log.Printf("Actual Msgs/Sec: %d\n", rps(NumPubs, pubDur)) 271 | log.Printf("Actual Band/Sec: %v\n", bps(rps(NumPubs, pubDur)*MsgSize*2)) 272 | log.Printf("Minimum Latency: %v", fmtDur(durations[0])) 273 | log.Printf("Median Latency : %v", fmtDur(getMedian(durations))) 274 | log.Printf("Maximum Latency: %v", fmtDur(durations[len(durations)-1])) 275 | log.Printf("1st Sent Wall Time : %v", fmtDur(pubStart.Sub(start))) 276 | log.Printf("Last Sent Wall Time: %v", fmtDur(pubDur)) 277 | log.Printf("Last Recv Wall Time: %v", fmtDur(subDur)) 278 | } 279 | 280 | const fsecs = float64(time.Second) 281 | 282 | func rps(count int, elapsed time.Duration) int { 283 | return int(float64(count) / (float64(elapsed) / fsecs)) 284 | } 285 | 286 | // Just pretty print the byte sizes. 287 | func byteSize(n int) string { 288 | sizes := []string{"B", "K", "M", "G", "T"} 289 | base := float64(1024) 290 | if n < 10 { 291 | return fmt.Sprintf("%d%s", n, sizes[0]) 292 | } 293 | e := math.Floor(logn(float64(n), base)) 294 | suffix := sizes[int(e)] 295 | val := math.Floor(float64(n)/math.Pow(base, e)*10+0.5) / 10 296 | f := "%.0f%s" 297 | if val < 10 { 298 | f = "%.1f%s" 299 | } 300 | return fmt.Sprintf(f, val, suffix) 301 | } 302 | 303 | func bps(n int) string { 304 | sizes := []string{"Bps", "Kbps", "Mbps", "Gbps", "Tbps"} 305 | base := float64(1024) 306 | n *= 8 307 | if n < 10 { 308 | return fmt.Sprintf("%d%s", n, sizes[0]) 309 | } 310 | e := math.Floor(logn(float64(n), base)) 311 | suffix := sizes[int(e)] 312 | val := math.Floor(float64(n)/math.Pow(base, e)*10+0.5) / 10 313 | f := "%.0f%s" 314 | if val < 10 { 315 | f = "%.1f%s" 316 | } 317 | return fmt.Sprintf(f, val, suffix) 318 | } 319 | 320 | func logn(n, b float64) float64 { 321 | return math.Log(n) / math.Log(b) 322 | } 323 | 324 | // Make time durations a bit prettier. 325 | func fmtDur(t time.Duration) time.Duration { 326 | // e.g 234us, 4.567ms, 1.234567s 327 | return t.Truncate(time.Microsecond) 328 | } 329 | 330 | func getMedian(values []time.Duration) time.Duration { 331 | l := len(values) 332 | if l == 0 { 333 | log.Fatalf("empty set") 334 | } 335 | if l%2 == 0 { 336 | return (values[l/2-1] + values[l/2]) / 2 337 | } 338 | return values[l/2] 339 | } 340 | 341 | // writeRawFile creates a file with a list of recorded latency 342 | // measurements, one per line. 343 | func writeRawFile(filePath string, values []time.Duration) error { 344 | f, err := os.Create(filePath) 345 | if err != nil { 346 | return err 347 | } 348 | defer f.Close() 349 | for _, value := range values { 350 | fmt.Fprintf(f, "%f\n", float64(value.Nanoseconds())/1000000.0) 351 | } 352 | return nil 353 | } 354 | -------------------------------------------------------------------------------- /terraform/.gitignore: -------------------------------------------------------------------------------- 1 | terraform-account.json 2 | terraform.tfvars 3 | 4 | # Local .terraform directories 5 | **/.terraform/* 6 | 7 | # .tfstate files 8 | *.tfstate 9 | *.tfstate.* 10 | 11 | # Crash log files 12 | crash.log 13 | 14 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 15 | # .tfvars files are managed as part of configuration and so should be included in 16 | # version control. 17 | # 18 | # example.tfvars 19 | 20 | -------------------------------------------------------------------------------- /terraform/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Installing and Running the NATS Latency Test 3 | 4 | To faciliate testing, we've provided terraforms scripts that will 5 | provision machine instances and run the latency tests. 6 | 7 | ## Prerequisites 8 | 9 | The only required tool is *terraform*. Terraform installation instructions 10 | can be found [here](https://www.terraform.io/intro/getting-started/install.html). 11 | 12 | This has been tested with terraform version 0.11.8. 13 | 14 | If you want to regenerate certificates for TLS, optionally you can install CFSSL. 15 | See the [TLS](##TLS) section below. 16 | 17 | You will need a GCP or Packet account and it is advised to have a dedicated cloud vendor project for this test. 18 | 19 | ## TLS 20 | 21 | The provided certificates should work with hostnames set by terraform, 22 | but if you find a need to update them you'll want to install 23 | [CFSSL](https://github.com/cloudflare/cfssl) and modify the relevant 24 | [configuration files](tls-scripts/config). The certificates can be 25 | regenerated to replace existing certificates by running the 26 | [gencerts.sh](./tls-scripts/gencerts.sh) script from inside the 27 | `tls-scripts` directory. 28 | 29 | ## Test Setup 30 | 31 | **First time usage**: The first time you are running these scripts you will 32 | need to run the `terraform init` command from the provider's directory. It is 33 | recommended to run `terraform init` every time before running `terraform apply`. 34 | 35 | Supported cloud providers include: 36 | 37 | * [GCP](gcp) 38 | * [Packet](packet) 39 | 40 | See the relevant `README.MD` files in the cloud vendor directories for specific vendor setup. 41 | 42 | ## Test Structure 43 | 44 | When executing this plan via terraform (e.g. via `terraform apply`), terraform will: 45 | 46 | * Provision a NATS server machine, `servera` 47 | * Provision a NATS server machine, `serverb` 48 | * Provision a test client machine, `client` 49 | * Install NATS servers, applications, scripts, certificates, and configuration 50 | * Route the NATS servers 51 | * Launch the NATS servers 52 | * Launch the default run of the latency tests 53 | * Print relevant information about server locations and monitoring urls 54 | 55 | This will setup up a latency test that can be envisioned as a triangle. 56 | 57 | ```text 58 | Server A - - - - - Server B 59 | \ / 60 | \ / 61 | \ / 62 | \ / 63 | \ / 64 | Latency Test (client) 65 | ``` 66 | 67 | WARNING: Unlike a lot of performance testing, by default this testing 68 | is aimed to simulate a secure production environment. 69 | 70 | To that end, this test is configured with: 71 | 72 | * NATS server clustering 73 | * End to End bidirectional TLS (both client and route connections) 74 | * Manual cipher suite overrides 75 | * Filtering of subjects between clustered servers 76 | * Authorization of clients and route connections 77 | * Publish and subscribe authorization for clients 78 | 79 | Adjust configuration files as necessary to mirror your environment. 80 | 81 | ## The latency test client 82 | 83 | Having the latency client as a single app own instance is the best way to 84 | measure end to end latency. As we are in the low microsecond range of 85 | measurements and measuring tail latency on higher end machines, we 86 | very precise time measurements. This requires sophisticated time 87 | synchronization or using a single machine instance to measure 88 | time. In the interest of simplicity and brevity, we chose the latter. 89 | 90 | ## Manually running the tests 91 | 92 | To manually run tests, ssh to the client machine, and run the [run_tests.sh](client/run_tests.sh) script. 93 | 94 | ## Thirdparty Results 95 | 96 | If you would like to contribute additional test results, we would welcome a PR that adds a `.MD` file describing your testing, environment, and (if applicable) steps to reproduce the test. 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /terraform/bootstrap/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Install go 4 | curl -o go.tar https://dl.google.com/go/go1.11.linux-amd64.tar.gz 5 | tar -xvf go.tar 1>/dev/null 6 | 7 | # Install git 8 | sudo apt-get update 9 | #sudo apt-get upgrade 10 | sudo apt-get -y install git 11 | sudo apt-get -y install zip unzip 12 | 13 | mkdir gopath 2>/dev/null 14 | 15 | # setup our environment 16 | . ~/setenv.sh 17 | 18 | # Install the NATS server and latency test 19 | echo "Installing NATS components." 20 | gnatsd_version=v1.3.0 21 | wget "https://github.com/nats-io/gnatsd/releases/download/$gnatsd_version/gnatsd-$gnatsd_version-linux-amd64.zip" -O tmp.zip 22 | unzip tmp.zip 23 | mv gnatsd-$gnatsd_version-linux-amd64/gnatsd gnatsd 24 | 25 | go get github.com/nats-io/go-nats 26 | go get github.com/nats-io/latency-tests 27 | -------------------------------------------------------------------------------- /terraform/bootstrap/run_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ./setenv.sh 4 | 5 | echo "Starting NATS server process." 6 | ./gnatsd -config gnatsd.conf 2>server.err 1>server.out & 7 | disown 8 | echo "Started NATS server." 9 | sleep 5 10 | -------------------------------------------------------------------------------- /terraform/bootstrap/setenv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export GOROOT=`pwd`/go 4 | export GOPATH=`pwd`/gopath 5 | 6 | export PATH=$GOROOT/bin:$PATH 7 | export PATH=$GOPATH/bin:$PATH 8 | -------------------------------------------------------------------------------- /terraform/client/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDxDCCAqygAwIBAgIUQ2j1yQRjp0+2ERFSklspxDBqyQ4wDQYJKoZIhvcNAQEL 3 | BQAwejELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdlbGVzMQswCQYDVQQH 4 | EwJDQTEQMA4GA1UEChMHU3luYWRpYTENMAsGA1UECxMETkFUUzEnMCUGA1UEAxMe 5 | Q3VzdG9tIE5BVFMgTGF0ZW5jeSBUZXN0aW5nIENBMB4XDTE4MDgyNzIxMDAwMFoX 6 | DTIzMDgyNjIxMDAwMFowejELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdl 7 | bGVzMQswCQYDVQQHEwJDQTEQMA4GA1UEChMHU3luYWRpYTENMAsGA1UECxMETkFU 8 | UzEnMCUGA1UEAxMeQ3VzdG9tIE5BVFMgTGF0ZW5jeSBUZXN0aW5nIENBMIIBIjAN 9 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArPPwC9uOiT/ALpLSZ9XMO6UzHkhb 10 | 8WfL75QYnBohBnqLPdjC6330fF5lwgi/XTs1aSROh/oZBvht8wyTjV9bwkJqD649 11 | R7kIEX8B0Mc23b3VMHDLU1sBgbi7GuoWMJMi9/x7e6+BCRU0KrwdxIgIPrd2rJ50 12 | 7p9R3h8DOCRUpFc5EaJsLeUTYfzFwmsTOk2RO7k/9VPmZYr4buezsGg+k+8DnIhW 13 | zhaxNZRmavCxRmwoIqNo5OqF6OG5cSzVSG7j9NrxB/EJ5nbg0gpoUX5MDOXvlpL1 14 | ED3253ZkGCzV5r2m/+l43LWUXecGA6/2rPql0ebFOVkg7KfT5xmx3nprSwIDAQAB 15 | o0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU 16 | qX2/Z4GrH3fLEOYFpjA7aO72BkEwDQYJKoZIhvcNAQELBQADggEBAAWK/9aXpfUH 17 | Zm1vBRvL+4sH7aX7QUx8CLyw/hROUKtFBdWEZP2M9Ld9rzKvtopLK2OIfXaJVmiL 18 | mkx/2XdiAJLEUi0ex4WLtn/XIdYU+q1WVoAANNXH4win6J89j2i7iAYAqZvtBwGj 19 | yGyfdNPJ/qzu77KDuUW7RfeId9st0fmUrGgvO1+uwLMw8X+8kg1Bmf3Is/FNzUGe 20 | 9KBuylWrClxtehwYbkFmhQ5DyHHcvYFTXGbMerILSX4u4y4qJ8dZOAemc09sxVW3 21 | HRoKbjnn6nXPLdqMEKMLpHHEfHNkWODDSO9FC8RubrIHg2DBs9pAxwo5nauCVhCh 22 | CDkL/HO5tvc= 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /terraform/client/client-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEoQIBAAKCAQEAwoIDRnwDsITOl1wBDfExkVsFZjX4rU78Ib4lQPj6cCavd/l6 3 | qf8RWWVtU0GFpPJwbJg6n2/0KnRDZci9nlOWF/1xb7kALxs5s5xZKgkUMLcYxdLt 4 | 5pgIgpB663uzJFEvR0wnW3OmOnxx8PaNBOaNIHI/4Vyoeq5l9Tk3EF+vPnImfo64 5 | psyCCxU5+QNBmqcUn5tOoFZtuv1Jo8IdLUABuiAWDII42EFJWX31bXD7BvdW4CIT 6 | O7ZQJT1U5hoFyDYsZXM1pDmeMYQVoIZsTV2I8NySLtsnRcUXr3BX9otMRAgMRJVp 7 | ldN2XEtYvRo50P5hBeNQTLj9CD2QLTFrhYW4CwIDAQABAoIBAQC1eEdGA34Nulpk 8 | rNnvABCW5Kzs533Tc9WYRabML364E9+xt3jSEb9GAHM3MfJWKjrplj1bc0ACO+aF 9 | l/wRMzrdtv+WlKuvR19WS5CEv2Ou76SVLG34re+CoPmNqiNAxt2tT0eI8yUre99y 10 | SRTYdaFFnFItGB24F+3YFEFjbWI6hvUwjTv1/SUTf4ufbg+2mTEuNvsqjxdomaMz 11 | n9+92nVspz78FURI6uMcRTvrihVOIb1HsItHFADqWrAnsZNlSbL0Grk3hw0MUOmY 12 | 6JorE+IDbak0HyNUNYr+GtBe1AyT40bkwlFmb1UsCQak374nbF/UKav9Vj/cVH11 13 | 67sO1UYBAoGBAN5VjVf6pUhnrJK09PzLZ0pIInHBeI4v7cm4lSbD2Y9SiwNx8VAK 14 | WkkAc1oI7/nEhScf6gEhDC2PcxPL2BxLq9BWmZ5cmq4vrJrUttPvmpOQxSx+KHkN 15 | hK39O2n0X5kTobssXtPqmxtxgPaN3ZT9AMX+xo5o5vk0UlWwMumzu5ahAoGBAN/1 16 | 0Ll0FBY7UkhYnUt0m9Wy6XdXeL6V8SM3f0dHBoEczXZnb3JXVaanDJUXpFaaaDls 17 | wmQzhUp781eAJB9RNeKMZdgu3f0oEVVxIa2E/fRwvVgVe2qlm7B0hMmXxeUyaPOC 18 | nu2oAGdlhc8EgSC6fZeKxhKMn9Fw4+tL8/PB+osrAoGAN77boaOGrZDRBDe69WdK 19 | jqVnfX406/G4fUt6mi2g7v6TPFnlV1xBJuyl/30eLlHH0Pd/hKj0lLfS8rO5i96t 20 | RZ9xBPPTFLl/XZLYBGufJkC2L2GyZCevjLBhpT9QeOEjO/r0C85W9ZqP60HGvQRy 21 | nTI0NqC2yOUFf9ad7VrTPgECf1B8BoafMJjMuMVHE0AKp/YkVcKNrNbRC9ecGiGD 22 | ZNMBhtUGVwbAXAeIAP2TgXueAdahPzrDSSN7Z/gKFPEsPjEsQ21talmQDKqn/XJe 23 | WOV/nowJLFEnMsw3E4FfCb9UXmMkjfjaZ0rBMVU0STN50aikNopz/vtFlqL4qLLx 24 | AxkCgYAQskCuk9qSebD/A/Wj4zit5f9Nui78FI8ZvgCnRH5ux8Pv1HMX7bNmikJQ 25 | YsrmSPYAR5KMlAXgmUw0WNCuit2dD6L0M0yy2e4nhDRu4lOvBbNEwKuElDj0IOwA 26 | pgvu4ydt0Qz5jnUrd8V8AbrTlZShxc4/K3zzmwRViMQFB0VcPw== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /terraform/client/client.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID6jCCAtKgAwIBAgIUS/cD8eVLTBE6P2vXoBSjkWgqyGwwDQYJKoZIhvcNAQEL 3 | BQAwejELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdlbGVzMQswCQYDVQQH 4 | EwJDQTEQMA4GA1UEChMHU3luYWRpYTENMAsGA1UECxMETkFUUzEnMCUGA1UEAxMe 5 | Q3VzdG9tIE5BVFMgTGF0ZW5jeSBUZXN0aW5nIENBMB4XDTE4MDgyNzIxMDAwMFoX 6 | DTIzMDgyNjIxMDAwMFowQTELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdl 7 | bGVzMQswCQYDVQQHEwJDQTEPMA0GA1UEAxMGQ2xpZW50MIIBIjANBgkqhkiG9w0B 8 | AQEFAAOCAQ8AMIIBCgKCAQEAwoIDRnwDsITOl1wBDfExkVsFZjX4rU78Ib4lQPj6 9 | cCavd/l6qf8RWWVtU0GFpPJwbJg6n2/0KnRDZci9nlOWF/1xb7kALxs5s5xZKgkU 10 | MLcYxdLt5pgIgpB663uzJFEvR0wnW3OmOnxx8PaNBOaNIHI/4Vyoeq5l9Tk3EF+v 11 | PnImfo64psyCCxU5+QNBmqcUn5tOoFZtuv1Jo8IdLUABuiAWDII42EFJWX31bXD7 12 | BvdW4CITO7ZQJT1U5hoFyDYsZXM1pDmeMYQVoIZsTV2I8NySLtsnRcUXr3BX9otM 13 | RAgMRJVpldN2XEtYvRo50P5hBeNQTLj9CD2QLTFrhYW4CwIDAQABo4GgMIGdMA4G 14 | A1UdDwEB/wQEAwIFoDAZBgNVHSUEEjAQBgRVHSUABggrBgEFBQcDAjAMBgNVHRMB 15 | Af8EAjAAMB0GA1UdDgQWBBQeBM14d3sHOHNQiMRkquz/jXvrHDAfBgNVHSMEGDAW 16 | gBSpfb9ngasfd8sQ5gWmMDto7vYGQTAiBgNVHREEGzAZggZjbGllbnSCCWxvY2Fs 17 | aG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAXnvwN2V5aB6ZTJTZrZ61ZWlu 18 | AwElNg2LO2eOgxYypxQAfRu8urgEkUB9nP+hBYkkw1QA5JP/nV+9+S8Uq8y/Fw6A 19 | QTXeWaVgCn5qAOi5Hke0PMGth8/y0LkNb2I/BGOGw9q66qn1FaMjh0tbkaxkLGt7 20 | 3iqUQgNOiIJqvw1g2+xfYi91IRhGlM9mtvtI29fl6wRKXQiDNOv4X0Ya4FnHPEii 21 | H8MV2GliUjQOFlyE+9uok/9Hl90whhEBWgBAv51O4S/WjsUpKFHH8TuoGDZr8BaC 22 | xRrVwvZGsb2hp3z20Ghj7j7/QrCVE3wJPzXCJmfDdOZjPT2cMz1w/WqY78VQRw== 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /terraform/client/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ./setenv.sh 4 | 5 | dur="5s" 6 | tlsvars="--secure -tls_ca ca.pem -tls_cert client.pem -tls_key client-key.pem" 7 | 8 | runtest() { 9 | latency-tests -sa nats://luser:top_secret@servera:4222 -sb nats://luser:top_secret@serverb:4222 -sz $msgsize -tr $msgrate -tt $dur $tlsvars -hist lat_${msgsize}b_by_${msgrate}_mps 10 | } 11 | 12 | # 13 | # for each message size we want to test, run iterations of different rates 14 | # 15 | declare -a arr=("256" "512" "1024" "4096") 16 | for i in "${arr[@]}" 17 | do 18 | msgsize="$i" 19 | 20 | msgrate="1000" 21 | runtest 22 | 23 | msgrate="10000" 24 | runtest 25 | 26 | msgrate="100000" 27 | runtest 28 | done 29 | -------------------------------------------------------------------------------- /terraform/gcp/README.md: -------------------------------------------------------------------------------- 1 | # NATS Latency Testing on GCP 2 | 3 | ## Getting Started 4 | 5 | A prerequisite to running this test on GCP is to setup a GCP account that can run 6 | 7 | 1. Create a GCP account and project. 8 | 2. Generate an account.json file, as described [here].(https://medium.com/@josephbleroy/using-terraform-with-google-cloud-platform-part-1-n-6b5e4074c059) 9 | 3. Enable the compute engine API and ensure proper permissions are set. 10 | 11 | ## Setting up and running the test 12 | 13 | We recommend always executing `terraform init` before applying the terraform 14 | configuration. 15 | 16 | Once all of the permissions and keys are setup, you can run the test. From this 17 | directory, run `terraform apply`. 18 | 19 | This will setup the latency tests described in the higher level terraform [README.md](../readme.md). 20 | 21 | Next, SSH to the client machine and run tests. The `run_tests.sh` runs a series of tests and provides a good starting point. 22 | 23 | ### Variables 24 | 25 | You can enter the variables via command line, manually when you run the test, or create a `terraform.tfvars` file with your variables required to run. You can override other 26 | variables found in [variables.tf](variables.tf) 27 | 28 | Here is an example: 29 | 30 | ```text 31 | project="nats-latency-testing" 32 | account_json_file="terraform-account.json" 33 | username="colin" 34 | server_type = "f1-micro" 35 | client_type = "f1-micro" 36 | 37 | # You can override other variables 38 | # e.g. 39 | # private_key_file = "gce_private_key.pem" 40 | # zone = "asia-south1" 41 | # region = "asia-south1-c" 42 | ``` -------------------------------------------------------------------------------- /terraform/gcp/main.tf: -------------------------------------------------------------------------------- 1 | 2 | provider "google" { 3 | credentials = "${file("${var.account_json_file}")}" 4 | project = "${var.project}" 5 | region = "${var.region}" 6 | } 7 | 8 | resource "google_compute_network" "lattest-network" { 9 | name = "lattest-network" 10 | auto_create_subnetworks = true 11 | } 12 | 13 | resource "google_compute_firewall" "lattest-firewall" { 14 | name = "lattest-firewall" 15 | network = "lattest-network" 16 | 17 | allow { 18 | protocol = "icmp" 19 | } 20 | 21 | allow { 22 | protocol = "tcp" 23 | ports = ["22", "4222", "4244", "8222"] 24 | } 25 | 26 | depends_on = ["google_compute_network.lattest-network"] 27 | } 28 | 29 | # Create a new instance 30 | resource "google_compute_instance" "servera" { 31 | name = "servera" 32 | machine_type = "${var.server_type}" 33 | zone = "${var.zone}" 34 | boot_disk { 35 | initialize_params { 36 | image = "ubuntu-1604-lts" 37 | } 38 | } 39 | 40 | network_interface { 41 | network = "lattest-network" 42 | access_config {} 43 | } 44 | 45 | service_account { 46 | scopes = ["userinfo-email", "compute-ro", "storage-ro"] 47 | } 48 | 49 | depends_on = ["google_compute_network.lattest-network"] 50 | } 51 | 52 | resource "google_compute_instance" "serverb" { 53 | name = "serverb" 54 | machine_type = "${var.server_type}" 55 | min_cpu_platform = "${var.min_cpu_platform}" 56 | zone = "${var.zone}" 57 | boot_disk { 58 | initialize_params { 59 | image = "ubuntu-1604-lts" 60 | } 61 | } 62 | 63 | network_interface { 64 | network = "lattest-network" 65 | access_config {} 66 | } 67 | 68 | service_account { 69 | scopes = ["userinfo-email", "compute-ro", "storage-ro"] 70 | } 71 | 72 | depends_on = ["google_compute_network.lattest-network"] 73 | } 74 | 75 | resource "google_compute_instance" "client" { 76 | name = "client" 77 | machine_type = "${var.client_type}" 78 | min_cpu_platform = "${var.min_cpu_platform}" 79 | zone = "${var.zone}" 80 | boot_disk { 81 | initialize_params { 82 | image = "ubuntu-1604-lts" 83 | } 84 | } 85 | 86 | network_interface { 87 | network = "lattest-network" 88 | access_config {} 89 | } 90 | 91 | service_account { 92 | scopes = ["userinfo-email", "compute-ro", "storage-ro"] 93 | } 94 | 95 | depends_on = ["google_compute_network.lattest-network"] 96 | } 97 | 98 | resource "null_resource" "client_update" { 99 | # Not perfect, but any changes to any instance of the machines 100 | # requires updates 101 | triggers { 102 | cluster_instance_ids = "${google_compute_instance.client.id}, ${google_compute_instance.servera.id}, ${google_compute_instance.serverb.id}" 103 | } 104 | 105 | # Bootstrap script can run on any instance of the cluster 106 | # So we just choose the first in this case 107 | connection { 108 | host = "${google_compute_instance.client.network_interface.0.access_config.0.nat_ip}" 109 | type = "ssh" 110 | user = "${var.username}" 111 | private_key = "${file("${var.private_key_file}")}" 112 | } 113 | 114 | # Copy our install script to the machine 115 | provisioner "file" { 116 | source = "../bootstrap/" 117 | destination = "/home/${var.username}" 118 | } 119 | 120 | provisioner "file" { 121 | source = "../client/" 122 | destination = "/home/${var.username}" 123 | } 124 | 125 | provisioner "remote-exec" { 126 | inline = [ 127 | "chmod +x /home/${var.username}/*.sh", 128 | "/home/${var.username}/install.sh", 129 | ] 130 | } 131 | 132 | depends_on = ["google_compute_instance.client"] 133 | } 134 | 135 | resource "null_resource" "servera_update" { 136 | # Not perfect, but any changes to any instance of the machines 137 | # requires updates 138 | triggers { 139 | cluster_instance_ids = "${google_compute_instance.client.id}, ${google_compute_instance.servera.id}, ${google_compute_instance.serverb.id}" 140 | } 141 | 142 | connection { 143 | host = "${google_compute_instance.servera.network_interface.0.access_config.0.nat_ip}" 144 | type = "ssh" 145 | user = "${var.username}" 146 | private_key = "${file("${var.private_key_file}")}" 147 | } 148 | 149 | # Copy our install script to the machine 150 | provisioner "file" { 151 | source = "../bootstrap/" 152 | destination = "/home/${var.username}" 153 | } 154 | 155 | provisioner "file" { 156 | source = "../servera/" 157 | destination = "/home/${var.username}" 158 | } 159 | 160 | provisioner "remote-exec" { 161 | # Add private_ip of each server in the cluster 162 | inline = [ 163 | "chmod +x /home/${var.username}/*.sh", 164 | "/home/${var.username}/install.sh", 165 | "/home/${var.username}/run_server.sh" 166 | ] 167 | } 168 | 169 | depends_on = ["google_compute_instance.servera"] 170 | } 171 | 172 | resource "null_resource" "serverb_update" { 173 | # Not perfect, but any changes to any instance of the machines 174 | # requires updates 175 | triggers { 176 | cluster_instance_ids = "${google_compute_instance.client.id}, ${google_compute_instance.servera.id}, ${google_compute_instance.serverb.id}" 177 | } 178 | 179 | connection { 180 | host = "${google_compute_instance.serverb.network_interface.0.access_config.0.nat_ip}" 181 | type = "ssh" 182 | user = "${var.username}" 183 | private_key = "${file("${var.private_key_file}")}" 184 | } 185 | 186 | # Copy our install script to the machine 187 | provisioner "file" { 188 | source = "../bootstrap/" 189 | destination = "/home/${var.username}" 190 | } 191 | 192 | provisioner "file" { 193 | source = "../serverb/" 194 | destination = "/home/${var.username}" 195 | } 196 | 197 | provisioner "remote-exec" { 198 | inline = [ 199 | "chmod +x /home/${var.username}/*.sh", 200 | "/home/${var.username}/install.sh", 201 | "/home/${var.username}/run_server.sh" 202 | ] 203 | } 204 | 205 | depends_on = ["google_compute_instance.serverb"] 206 | } -------------------------------------------------------------------------------- /terraform/gcp/output.tf: -------------------------------------------------------------------------------- 1 | output "client_internal_ip" { 2 | value = "${google_compute_instance.client.network_interface.0.address}" 3 | } 4 | 5 | output "client_external_ip" { 6 | value = "${google_compute_instance.client.network_interface.0.access_config.0.nat_ip}" 7 | } 8 | 9 | output "server_a_internal_ip" { 10 | value = "${google_compute_instance.servera.network_interface.0.address}" 11 | } 12 | 13 | output "server_a_external_ip" { 14 | value = "${google_compute_instance.servera.network_interface.0.access_config.0.nat_ip}" 15 | } 16 | 17 | output "server_b_internal_ip" { 18 | value = "${google_compute_instance.serverb.network_interface.0.address}" 19 | } 20 | output "server_b_external_ip" { 21 | value = "${google_compute_instance.serverb.network_interface.0.access_config.0.nat_ip}" 22 | } 23 | 24 | output "server_b_monitor_url" { 25 | value = "http://${google_compute_instance.serverb.network_interface.0.access_config.0.nat_ip}:8222" 26 | } 27 | 28 | output "server_a_monitor_url" { 29 | value = "http://${google_compute_instance.servera.network_interface.0.access_config.0.nat_ip}:8222" 30 | } 31 | 32 | -------------------------------------------------------------------------------- /terraform/gcp/variables.tf: -------------------------------------------------------------------------------- 1 | # GCE Project ID 2 | variable project {} 3 | 4 | # This is the account json credentials file with your private key and 5 | # other credentials. 6 | variable account_json_file {} 7 | # GCE username used to connect to the instance. 8 | # This must be in the private key. 9 | variable username {} 10 | 11 | # Private key for the ssh connection to the GCE instances for 12 | # the user define in "username" 13 | variable private_key_file { 14 | default = "~/.ssh/google_compute_engine" 15 | } 16 | 17 | # 18 | # Machine type reference (July 2018) 19 | # gcloud compute machine-types list | grep us-west-2a 20 | # NAME ZONE CPUS MEMORY_GB DEPRECATED 21 | # f1-micro us-west2-a 1 0.60 22 | # g1-small us-west2-a 1 1.70 23 | # n1-highcpu-16 us-west2-a 16 14.40 24 | # n1-highcpu-2 us-west2-a 2 1.80 25 | # n1-highcpu-32 us-west2-a 32 28.80 26 | # n1-highcpu-4 us-west2-a 4 3.60 27 | # n1-highcpu-64 us-west2-a 64 57.60 28 | # n1-highcpu-8 us-west2-a 8 7.20 29 | # n1-highcpu-96 us-west2-a 96 86.40 30 | # n1-highmem-16 us-west2-a 16 104.00 31 | # n1-highmem-2 us-west2-a 2 13.00 32 | # n1-highmem-32 us-west2-a 32 208.00 33 | # n1-highmem-4 us-west2-a 4 26.00 34 | # n1-highmem-64 us-west2-a 64 416.00 35 | # n1-highmem-8 us-west2-a 8 52.00 36 | # n1-highmem-96 us-west2-a 96 624.00 37 | # n1-standard-1 us-west2-a 1 3.75 38 | # n1-standard-16 us-west2-a 16 60.00 39 | # n1-standard-2 us-west2-a 2 7.50 40 | # n1-standard-32 us-west2-a 32 120.00 41 | # n1-standard-4 us-west2-a 4 15.00 42 | # n1-standard-64 us-west2-a 64 240.00 43 | # n1-standard-8 us-west2-a 8 30.00 44 | # n1-standard-96 us-west2-a 96 360.00 45 | 46 | variable server_type { 47 | default = "n1-highcpu-2" 48 | } 49 | 50 | variable client_type { 51 | default = "n1-highcpu-2" 52 | } 53 | 54 | # CPU Platform options include: 55 | # Intel Xeon E5 (Sandy Bridge) processors: "Intel Sandy Bridge" 56 | # Intel Xeon E5 v2 (Ivy Bridge) processors: "Intel Ivy Bridge" 57 | # Intel Xeon E5 v3 (Haswell) processors: "Intel Haswell" 58 | # Intel Xeon E5 v4 (Broadwell) processors: "Intel Broadwell" 59 | # Intel Xeon (Skylake) processors: "Intel Skylake" 60 | variable min_cpu_platform { 61 | default = "Intel Skylake" 62 | } 63 | 64 | variable zone { 65 | default = "us-west2-a" 66 | } 67 | 68 | variable region { 69 | default = "us-west2" 70 | } -------------------------------------------------------------------------------- /terraform/packet/README.md: -------------------------------------------------------------------------------- 1 | 2 | # NATS Latency Testing on Packet 3 | 4 | ## Getting started 5 | 6 | You'll need a packet account and and project setup to run the latency tests. 7 | Once you have generated an API key from the user profile or project section 8 | of your Packet account, you'll need to set the `auth_token` and `project_id` 9 | variables. More on that below. 10 | 11 | ## Setting up and running tests 12 | 13 | We recommend always executing `terraform init` before applying the terraform 14 | configuration. 15 | 16 | Once all of the permissions and keys are setup, you can run the test. From this 17 | directory, run `terraform apply`. 18 | 19 | This will setup the latency tests described in the higher level terraform [README.md](../readme.md). 20 | 21 | Next, SSH to the client machine and run tests. The `run_tests.sh` runs a series of tests and provides a good starting point. 22 | 23 | ## Variables 24 | 25 | You can enter the variables via command line, manually when you run the test, 26 | or create a `terraform.tfvars` file with your variables required to run. You 27 | can override other variables found in [variables.tf](variables.tf) 28 | 29 | Different machine instances can be selected using the `server_type` 30 | and `client_type` variables. e.g. Descriptions of available machines can 31 | be found in comments of the `variables.tf` file, although you may want to 32 | check for updates. More information on terraform packet device types can 33 | be found [here](https://www.terraform.io/docs/providers/packet/r/device.html) 34 | 35 | Here is an example: 36 | 37 | ```text 38 | auth_token="AB23cdeFFgH123lmnopQRstuv134wxyz" 39 | server_type = "baremetal_0" 40 | client_type = "baremetal_1" 41 | project_id="1234567a-1aa1-2bb2-3c3c-0n0a0t0s0ZZZ" 42 | ``` 43 | 44 | ## Running the tests 45 | 46 | To run the default tests simply run: 47 | `ssh root@ "~/run_tests.sh"` 48 | 49 | This assumes you have added your key to your local keychain. If not you 50 | may need to use the `-i` option or ssh into the client machine directly. -------------------------------------------------------------------------------- /terraform/packet/main.tf: -------------------------------------------------------------------------------- 1 | # Configure the Packet Provider 2 | provider "packet" { 3 | auth_token = "${var.auth_token}" 4 | } 5 | 6 | # Create a device for the server and add it to our project 7 | resource "packet_device" "nats_server_a" { 8 | hostname = "servera" 9 | plan = "${var.server_type}" 10 | facility = "${var.facility}" 11 | operating_system = "ubuntu_18_04" 12 | billing_cycle = "hourly" 13 | project_id = "${var.project_id}" 14 | } 15 | 16 | resource "packet_device" "nats_server_b" { 17 | hostname = "serverb" 18 | plan = "${var.server_type}" 19 | facility = "${var.facility}" 20 | operating_system = "ubuntu_18_04" 21 | billing_cycle = "hourly" 22 | project_id = "${var.project_id}" 23 | } 24 | 25 | # Create devices for the latency clients and add it to our 26 | # project 27 | resource "packet_device" "nats_client" { 28 | hostname = "client" 29 | plan = "${var.client_type}" 30 | facility = "${var.facility}" 31 | operating_system = "ubuntu_18_04" 32 | billing_cycle = "hourly" 33 | project_id = "${var.project_id}" 34 | } 35 | 36 | resource "null_resource" "client_update" { 37 | # Not perfect, but any changes to any instance of the machines 38 | # requires updates 39 | triggers { 40 | cluster_instance_ids = "${packet_device.nats_client.id}, ${packet_device.nats_server_a.id}, ${packet_device.nats_server_b.id}" 41 | } 42 | 43 | # Bootstrap script can run on any instance of the cluster 44 | # So we just choose the first in this case 45 | connection { 46 | host = "${lookup(packet_device.nats_client.0.network[0], "address")}" 47 | } 48 | 49 | provisioner "file" { 50 | source = "../bootstrap/" 51 | destination = "~/" 52 | } 53 | 54 | provisioner "file" { 55 | source = "../client/" 56 | destination = "~/" 57 | } 58 | provisioner "remote-exec" { 59 | # Add private_ip of each server in the cluster 60 | inline = [ 61 | "chmod +x ~/*.sh", 62 | "~/install.sh", 63 | "echo '${lookup(packet_device.nats_server_a.0.network[2], "address")} servera servera.latency.nats.com' >> /etc/hosts ", 64 | "echo '${lookup(packet_device.nats_server_b.0.network[2], "address")} serverb serverb.latency.nats.com' >> /etc/hosts ", 65 | ] 66 | } 67 | 68 | depends_on = ["packet_device.nats_server_a", "packet_device.nats_server_b", "packet_device.nats_client"] 69 | } 70 | 71 | ## 72 | ## This next set of resources updates the /etc/host files so 73 | ## we can have a static nats server config. 74 | ## 75 | resource "null_resource" "servera_update" { 76 | # Not perfect, but any changes to any instance of the machines 77 | # requires updates 78 | triggers { 79 | cluster_instance_ids = "${packet_device.nats_client.id}, ${packet_device.nats_server_a.id}, ${packet_device.nats_server_b.id}" 80 | } 81 | 82 | # Bootstrap script can run on any instance of the cluster 83 | # So we just choose the first in this case 84 | connection { 85 | host = "${lookup(packet_device.nats_server_a.0.network[0], "address")}" 86 | } 87 | 88 | # Copy our install scripts to the machine 89 | provisioner "file" { 90 | source = "../bootstrap/" 91 | destination = "~/" 92 | } 93 | 94 | provisioner "file" { 95 | source = "../servera/" 96 | destination = "~/" 97 | } 98 | provisioner "remote-exec" { 99 | # Add private_ip of each server in the cluster 100 | inline = [ 101 | "chmod +x ~/*.sh", 102 | "~/install.sh", 103 | "echo '${lookup(packet_device.nats_client.0.network[2], "address")} client client.latency.nats.com' >> /etc/hosts ", 104 | "echo '${lookup(packet_device.nats_server_b.0.network[2], "address")} serverb serverb.latency.nats.com' >> /etc/hosts ", 105 | "~/run_server.sh", 106 | ] 107 | } 108 | 109 | depends_on = ["packet_device.nats_server_a", "packet_device.nats_server_b", "packet_device.nats_client"] 110 | } 111 | 112 | resource "null_resource" "serverb_update" { 113 | # Not perfect, but any changes to any instance of the machines 114 | # requires updates 115 | triggers { 116 | cluster_instance_ids = "${packet_device.nats_client.id}, ${packet_device.nats_server_a.id}, ${packet_device.nats_server_b.id}" 117 | } 118 | 119 | # Bootstrap script can run on any instance of the cluster 120 | # So we just choose the first in this case 121 | connection { 122 | host = "${lookup(packet_device.nats_server_b.0.network[0], "address")}" 123 | } 124 | 125 | # Copy our install script to the machine 126 | provisioner "file" { 127 | source = "../bootstrap/" 128 | destination = "~/" 129 | } 130 | 131 | provisioner "file" { 132 | source = "../serverb/" 133 | destination = "~/" 134 | } 135 | 136 | provisioner "remote-exec" { 137 | # Add private_ip of each server in the cluster 138 | inline = [ 139 | "chmod +x ~/*.sh", 140 | "~/install.sh", 141 | "echo '${lookup(packet_device.nats_client.0.network[2], "address")} client client.latency.nats.com' >> /etc/hosts ", 142 | "echo '${lookup(packet_device.nats_server_a.0.network[2], "address")} servera servera.latency.nats.com' >> /etc/hosts ", 143 | "~/run_server.sh", 144 | ] 145 | } 146 | 147 | depends_on = ["packet_device.nats_server_a", "packet_device.nats_server_b", "packet_device.nats_client"] 148 | } 149 | -------------------------------------------------------------------------------- /terraform/packet/output.tf: -------------------------------------------------------------------------------- 1 | output "client_internal_ip" { 2 | value = "${lookup(packet_device.nats_client.0.network[2], "address")}" 3 | } 4 | 5 | output "client_external_ip" { 6 | value = "${lookup(packet_device.nats_client.0.network[0], "address")}" 7 | } 8 | 9 | output "server_a_internal_ip" { 10 | value = "${lookup(packet_device.nats_server_a.0.network[2], "address")}" 11 | } 12 | 13 | output "server_a_external_ip" { 14 | value = "${lookup(packet_device.nats_server_a.0.network[0], "address")}" 15 | } 16 | 17 | output "server_b_external_ip" { 18 | value = "${lookup(packet_device.nats_server_b.0.network[0], "address")}" 19 | } 20 | 21 | output "server_b_monitor_url" { 22 | value = "http://${lookup(packet_device.nats_server_b.0.network[0], "address")}:8222" 23 | } 24 | 25 | output "server_a_monitor_url" { 26 | value = "http://${lookup(packet_device.nats_server_a.0.network[0], "address")}:8222" 27 | } 28 | 29 | output "server_b_internal_ip" { 30 | value = "${lookup(packet_device.nats_server_b.0.network[2], "address")}" 31 | } 32 | -------------------------------------------------------------------------------- /terraform/packet/variables.tf: -------------------------------------------------------------------------------- 1 | # User must define this 2 | variable auth_token {} 3 | 4 | # project ID to use, found under project settings. e.g. 9999999-abcd-ef00-1234-567abcde 5 | variable project_id {} 6 | 7 | # 8 | # Machine type reference (July 2018) 9 | # 10 | # "c2.medium.x86","c2.medium.x86", "Our c2.medium.x86 configuration is an AMD 7401P EPYC server.", 11 | # "m2.xlarge.x86","m2.xlarge.x86","Our m2.xlarge.x86 configuration is a...", 12 | # "storage_1","Standard","TBD" 13 | # "storage_2","Performance","TBD", 14 | # "baremetal_2a","c1.large.arm","Our Type 2A configuration is a 96-core dual socket ARM 64 beast based on Cavium ThunderX chips", 15 | # "baremetal_1","c1.small.x86","Our Type 1 configuration is a zippy general use server, with an Intel E3-1240 v3 processor and 32GB of RAM.", 16 | # "baremetal_3","c1.xlarge.x86","Our Type 3 configuration is a high core, high IO server, with dual Intel E5-2640 v3 processors, 128GB of DDR4 RAM and ultra fast NVME flash drives.", 17 | # "baremetal_2","m1.xlarge.x86","Our Type 2 configuration is the perfect all purpose virtualization server, with dual E5-2650 v4 processors, 256 GB of DDR4 RAM, and six SSDs totaling 2.8 TB of storage.", 18 | # "baremetal_s","s1.large.x86","Our Type S server packs in 24TB of storage and is perfect for large object or file needs.", 19 | # "baremetal_0","t1.small.x86", "Our Type 0 configuration is a general use \"cloud killer\" server, with a Intel Atom 2.4Ghz processor and 8GB of RAM.", 20 | # "baremetal_1e", "x1.small.x86","Our Type 1e ...", 21 | 22 | variable server_type { 23 | default = "baremetal_1" 24 | } 25 | 26 | variable client_type { 27 | default = "baremetal_1" 28 | } 29 | 30 | # As of 8/28/2018 31 | # Toronto, ON, CA "yyz1" 32 | # Tokyo, JP "nrt1" 33 | # Atlanta, GA "atl1" 34 | # Hong Kong 1, HK "hkg1" 35 | # Los Angeles, CA "lax1" 36 | # Dallas, TX "dfw1" 37 | # Amsterdam, NL "ams1" 38 | # Parsippany, NJ "ewr1" 39 | # Singapore "sin1" 40 | # Sydney, Australia "syd1" 41 | # Chicago, IL "ord1" 42 | # Ashburn, VA "iad1" 43 | # Sunnyvale, CA "sjc1" 44 | # Frankfurt, DE "fra1" 45 | # Seattle, WA "sea1" 46 | variable facility { 47 | default = "sjc1" 48 | } 49 | -------------------------------------------------------------------------------- /terraform/servera/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDxDCCAqygAwIBAgIUQ2j1yQRjp0+2ERFSklspxDBqyQ4wDQYJKoZIhvcNAQEL 3 | BQAwejELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdlbGVzMQswCQYDVQQH 4 | EwJDQTEQMA4GA1UEChMHU3luYWRpYTENMAsGA1UECxMETkFUUzEnMCUGA1UEAxMe 5 | Q3VzdG9tIE5BVFMgTGF0ZW5jeSBUZXN0aW5nIENBMB4XDTE4MDgyNzIxMDAwMFoX 6 | DTIzMDgyNjIxMDAwMFowejELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdl 7 | bGVzMQswCQYDVQQHEwJDQTEQMA4GA1UEChMHU3luYWRpYTENMAsGA1UECxMETkFU 8 | UzEnMCUGA1UEAxMeQ3VzdG9tIE5BVFMgTGF0ZW5jeSBUZXN0aW5nIENBMIIBIjAN 9 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArPPwC9uOiT/ALpLSZ9XMO6UzHkhb 10 | 8WfL75QYnBohBnqLPdjC6330fF5lwgi/XTs1aSROh/oZBvht8wyTjV9bwkJqD649 11 | R7kIEX8B0Mc23b3VMHDLU1sBgbi7GuoWMJMi9/x7e6+BCRU0KrwdxIgIPrd2rJ50 12 | 7p9R3h8DOCRUpFc5EaJsLeUTYfzFwmsTOk2RO7k/9VPmZYr4buezsGg+k+8DnIhW 13 | zhaxNZRmavCxRmwoIqNo5OqF6OG5cSzVSG7j9NrxB/EJ5nbg0gpoUX5MDOXvlpL1 14 | ED3253ZkGCzV5r2m/+l43LWUXecGA6/2rPql0ebFOVkg7KfT5xmx3nprSwIDAQAB 15 | o0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU 16 | qX2/Z4GrH3fLEOYFpjA7aO72BkEwDQYJKoZIhvcNAQELBQADggEBAAWK/9aXpfUH 17 | Zm1vBRvL+4sH7aX7QUx8CLyw/hROUKtFBdWEZP2M9Ld9rzKvtopLK2OIfXaJVmiL 18 | mkx/2XdiAJLEUi0ex4WLtn/XIdYU+q1WVoAANNXH4win6J89j2i7iAYAqZvtBwGj 19 | yGyfdNPJ/qzu77KDuUW7RfeId9st0fmUrGgvO1+uwLMw8X+8kg1Bmf3Is/FNzUGe 20 | 9KBuylWrClxtehwYbkFmhQ5DyHHcvYFTXGbMerILSX4u4y4qJ8dZOAemc09sxVW3 21 | HRoKbjnn6nXPLdqMEKMLpHHEfHNkWODDSO9FC8RubrIHg2DBs9pAxwo5nauCVhCh 22 | CDkL/HO5tvc= 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /terraform/servera/gnatsd.conf: -------------------------------------------------------------------------------- 1 | log_file: "gnatsd.log" 2 | http: 8222 3 | 4 | tls { 5 | cert_file: "./servera.pem" 6 | key_file: "./servera-key.pem" 7 | ca_file: "./ca.pem" 8 | timeout: 2 9 | cipher_suites: [ 10 | "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" 11 | ] 12 | } 13 | 14 | authorization { 15 | user: luser 16 | # bcypted hash of "top_secret" 17 | password: $2a$11$UaoHwUEqHaMwqo6L4kM2buOBnGFnSCWxNXY87hl.kCERqKK8WAXM. 18 | timeout: 3 19 | permissions { 20 | publish: "_INBOX.*" 21 | } 22 | } 23 | 24 | cluster { 25 | listen: 4244 26 | 27 | tls { 28 | ca_file: "./ca.pem" 29 | cert_file: "./servera.pem" 30 | key_file: "./servera-key.pem" 31 | timeout: 3 32 | cipher_suites: [ 33 | "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" 34 | ] 35 | } 36 | 37 | authorization { 38 | user: ruser 39 | # bcypted hash of "top_secret" 40 | password: $2a$11$UaoHwUEqHaMwqo6L4kM2buOBnGFnSCWxNXY87hl.kCERqKK8WAXM. 41 | timeout: 3 42 | permissions { 43 | export: "_INBOX.*" 44 | } 45 | } 46 | 47 | routes = [ 48 | nats-route://ruser:top_secret@serverb:4244 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /terraform/servera/servera-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAmoKcqd0MDaE9aIN16/UwmVM7/ml3HUShg+PLlGzl8aYrMVbT 3 | CHCiKXaTNa4qT+Ay30DwE3cXU1SFoP/WDFuwecMFl4z15csnFNCtQzLdoI1SIFUH 4 | c+IUPqCdpYV5l5l4dvAfVAZCFW19hwgHsjC23OMhjFIPq7VvARbTyQo0GTaw+VfH 5 | jflu5Spk8eVUlFBgoSrgeprNf7PF/QRYwbkTdvOBawMr/dVHXumnqoCvSmXTbXmV 6 | wACjAjPhhFphEDMT2IKExBPn5XB3HZ383UmCi5BGPFlXQhVci1j8REDyUqnFmchH 7 | PB8TpYwJq4fdHmd+erU5pxQGil55hz2GFC6XYwIDAQABAoIBAESPICTfSLHjkfQG 8 | IRUKPv5JyJ0i/w+lnGWBdpvtljqbmR7Tf+CG2e28B6YSGgRHX0tg7SY1+cun/YNr 9 | AfeJ18yvlJOioJnOgxDhZ4Ah2eWbz405LY1mC8WeT1Va3JFAMAvWkJAgFsKbSs/X 10 | 6FJQ+1MYFZLF9t4iK5c4IdFbDbMBuP1/lGAxKI6l9YZOlo2xo7pAqAIMwMhBcXUd 11 | HgLm7R6+L8nSl81rEpO748j6mPGlS0n2mxADSPOl8RYrtkmKGaRIKikAfOqt8Nys 12 | FaMD9CGMID7miLFeRCqJ8Pj61e4s2psSMEZbeVfWxWCIR5fgV4Cn+taWVB6Xjxmi 13 | uqmHpwECgYEAzXw3JSl5ppDDix0HyeoKpDvXezwUQ56tndg5zYqJjSzlz5td9aj7 14 | NLepwLEhBvU1hSHTcS63i/asNE88BwJr5tE3sO0lNOz7gQl387ersRbxaPdW4egb 15 | YPCRWlnraAlosAT4tFZMOmEWvdDAzmIlkSx19mOMOlqVpZW65NVu8lECgYEAwH5j 16 | 4ASHl+DGT/gu6WvfdtnFv4HPr8t0N9yL1jgy1ZwkPnPb2UxOELEfcJ1pN/cdUVST 17 | k5JbQGUNO9ruNhcSJupmzO1yEAvekdbDfSWsQ1tn2HQ0vxa6etuowTq6QnE7X3WR 18 | 2c/1XDs7OBInQklAdBfP40kDcUsT2jNpzUtnrXMCgYEAg44xKAOjtLYd2ySc5fKH 19 | GZqOXIGcX6ZpdRMH/sXhRpcmEoJf53VmTtv/PDSq9m9q8m8zldTZAizNFzhbMAmm 20 | 10G/K/DHz1ihtH1BZLGEpH4R1Kf14e/eB3Q9OuEyy4qqkXa9W4ecigu6qY/KwNcp 21 | QgZ7B2G4V2vDPx3bZ8IVo+ECgYAZOLZHZPCLQuVZFxC2fu7huLkDVbPrucG5jAk6 22 | gVSPzoylLjMRLsFPyJVxAP8HWTabMHTBsjyInHT2ccIijjVPqgjcMwRt+9Am1bf5 23 | jtUaYkCiCN/cZdL7RArBfrtm90UrRdFdc7UXZ59jwmUod0adr30Kr8dmscqhHXlw 24 | b7/e5wKBgQCqB3fN7pRH2zN/WXdGTGJYWTFeVA2IepUz6piN1sjda1P59mKlyeIq 25 | U09i/CvVabpiEgzERO/AEJd8jwdVl9JPGyHXlnBtkbwWHFDMsaW4uzm5Jk8YVNeF 26 | 2hGcjzobVAcG67EwWLLvD/06FC55fwQeIirtm3RXy2LQHY6PqsafDA== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /terraform/servera/servera.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID/DCCAuSgAwIBAgIUNLkiLMHAcATXqIbKZl1tLCXXO8EwDQYJKoZIhvcNAQEL 3 | BQAwejELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdlbGVzMQswCQYDVQQH 4 | EwJDQTEQMA4GA1UEChMHU3luYWRpYTENMAsGA1UECxMETkFUUzEnMCUGA1UEAxMe 5 | Q3VzdG9tIE5BVFMgTGF0ZW5jeSBUZXN0aW5nIENBMB4XDTE4MDgyNzIxMDAwMFoX 6 | DTIzMDgyNjIxMDAwMFowSDELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdl 7 | bGVzMQswCQYDVQQHEwJDQTEWMBQGA1UEAxMNTkFUUyBzZXJ2ZXIgQTCCASIwDQYJ 8 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAJqCnKndDA2hPWiDdev1MJlTO/5pdx1E 9 | oYPjy5Rs5fGmKzFW0whwoil2kzWuKk/gMt9A8BN3F1NUhaD/1gxbsHnDBZeM9eXL 10 | JxTQrUMy3aCNUiBVB3PiFD6gnaWFeZeZeHbwH1QGQhVtfYcIB7IwttzjIYxSD6u1 11 | bwEW08kKNBk2sPlXx435buUqZPHlVJRQYKEq4HqazX+zxf0EWMG5E3bzgWsDK/3V 12 | R17pp6qAr0pl0215lcAAowIz4YRaYRAzE9iChMQT5+Vwdx2d/N1JgouQRjxZV0IV 13 | XItY/ERA8lKpxZnIRzwfE6WMCauH3R5nfnq1OacUBopeeYc9hhQul2MCAwEAAaOB 14 | qzCBqDAOBgNVHQ8BAf8EBAMCBaAwIwYDVR0lBBwwGgYEVR0lAAYIKwYBBQUHAwEG 15 | CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCbHjrp47AhRA48t6kz7 16 | vA7NC2YbMB8GA1UdIwQYMBaAFKl9v2eBqx93yxDmBaYwO2ju9gZBMCMGA1UdEQQc 17 | MBqCB3NlcnZlcmGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEA 18 | qiTFE6QYDEDpVZPtwT5hzzvoyTs4vQ2jEbIjRHSw2emDX/JnWnNi+1qfZF4d1wKL 19 | y+ohmpVfHxA1fGv9NhT6+sCJ2sUYpgLEaSeAnI4kArQIpIV41+8vCjCCAW8nJpZg 20 | /+exU5sYWLBY3nKKUm1RrE+CxSe5ZZw2PH2gxZ7HFVilPjQ61xUdaNMeG6AWZ72E 21 | 0HQ+FptTFPi3sPrbtGpc/5Vc/gRyUEurdVMkqq5XEPYLyQ5X0zTdOw1Jl7QNQ24a 22 | Nz7hwoHN6poz6rnNaFK74y+LMp80M/RDGHPBT2OeHXf8Ih8HC5GqPZsxgUBIpTZy 23 | X4j+/xubespqHCssQ/7jvA== 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /terraform/serverb/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDxDCCAqygAwIBAgIUQ2j1yQRjp0+2ERFSklspxDBqyQ4wDQYJKoZIhvcNAQEL 3 | BQAwejELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdlbGVzMQswCQYDVQQH 4 | EwJDQTEQMA4GA1UEChMHU3luYWRpYTENMAsGA1UECxMETkFUUzEnMCUGA1UEAxMe 5 | Q3VzdG9tIE5BVFMgTGF0ZW5jeSBUZXN0aW5nIENBMB4XDTE4MDgyNzIxMDAwMFoX 6 | DTIzMDgyNjIxMDAwMFowejELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdl 7 | bGVzMQswCQYDVQQHEwJDQTEQMA4GA1UEChMHU3luYWRpYTENMAsGA1UECxMETkFU 8 | UzEnMCUGA1UEAxMeQ3VzdG9tIE5BVFMgTGF0ZW5jeSBUZXN0aW5nIENBMIIBIjAN 9 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArPPwC9uOiT/ALpLSZ9XMO6UzHkhb 10 | 8WfL75QYnBohBnqLPdjC6330fF5lwgi/XTs1aSROh/oZBvht8wyTjV9bwkJqD649 11 | R7kIEX8B0Mc23b3VMHDLU1sBgbi7GuoWMJMi9/x7e6+BCRU0KrwdxIgIPrd2rJ50 12 | 7p9R3h8DOCRUpFc5EaJsLeUTYfzFwmsTOk2RO7k/9VPmZYr4buezsGg+k+8DnIhW 13 | zhaxNZRmavCxRmwoIqNo5OqF6OG5cSzVSG7j9NrxB/EJ5nbg0gpoUX5MDOXvlpL1 14 | ED3253ZkGCzV5r2m/+l43LWUXecGA6/2rPql0ebFOVkg7KfT5xmx3nprSwIDAQAB 15 | o0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU 16 | qX2/Z4GrH3fLEOYFpjA7aO72BkEwDQYJKoZIhvcNAQELBQADggEBAAWK/9aXpfUH 17 | Zm1vBRvL+4sH7aX7QUx8CLyw/hROUKtFBdWEZP2M9Ld9rzKvtopLK2OIfXaJVmiL 18 | mkx/2XdiAJLEUi0ex4WLtn/XIdYU+q1WVoAANNXH4win6J89j2i7iAYAqZvtBwGj 19 | yGyfdNPJ/qzu77KDuUW7RfeId9st0fmUrGgvO1+uwLMw8X+8kg1Bmf3Is/FNzUGe 20 | 9KBuylWrClxtehwYbkFmhQ5DyHHcvYFTXGbMerILSX4u4y4qJ8dZOAemc09sxVW3 21 | HRoKbjnn6nXPLdqMEKMLpHHEfHNkWODDSO9FC8RubrIHg2DBs9pAxwo5nauCVhCh 22 | CDkL/HO5tvc= 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /terraform/serverb/gnatsd.conf: -------------------------------------------------------------------------------- 1 | log_file: "gnatsd.log" 2 | http: 8222 3 | 4 | tls { 5 | cert_file: "./serverb.pem" 6 | key_file: "./serverb-key.pem" 7 | ca_file: "./ca.pem" 8 | timeout: 2 9 | cipher_suites: [ 10 | "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" 11 | ] 12 | } 13 | 14 | authorization { 15 | user: luser 16 | # bcypted hash of "top_secret" 17 | password: $2a$11$UaoHwUEqHaMwqo6L4kM2buOBnGFnSCWxNXY87hl.kCERqKK8WAXM. 18 | timeout: 3 19 | permissions { 20 | subscribe: "_INBOX.*" 21 | } 22 | } 23 | 24 | cluster { 25 | listen: 4244 26 | 27 | tls { 28 | ca_file: "./ca.pem" 29 | cert_file: "./serverb.pem" 30 | key_file: "./serverb-key.pem" 31 | timeout: 3 32 | cipher_suites: [ 33 | "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" 34 | ] 35 | } 36 | 37 | authorization { 38 | user: ruser 39 | # bcypted hash of "top_secret" 40 | password: $2a$11$UaoHwUEqHaMwqo6L4kM2buOBnGFnSCWxNXY87hl.kCERqKK8WAXM. 41 | timeout: 3 42 | permissions { 43 | import: "_INBOX.*" 44 | } 45 | } 46 | 47 | routes = [ 48 | nats-route://ruser:top_secret@servera:4244 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /terraform/serverb/serverb-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEAyBoSLX5dQ7BgRjEO7kVyR09Xov07E5e96GSZegML+kuFANhS 3 | tlGG9ey/df76YI3V1KYORlNn3SxoUta/km450jUg2wAVeHsjqsm59SRQXKFuZOvb 4 | BVEMMwGDpZhrfJ6IiDZwMEExhaqOu5OKQ+fYGnHT2Mi9M1w034ddi7MVBflPQHly 5 | px38drKtCt2IfYoj7QmszOcqM2Nf6ym1vAlhHxGzgaaow7eSzZ6u3s74smOeiHrq 6 | s47Yaj1wZqjgR2pIl6qpAs/uHVIRlVK3zk85X8EcsjpWromYgMrvPrReEYFByHeW 7 | xmgbGMX6k4/ORy6cIEKXj/b9j6Lsz6SLgg24lwIDAQABAoIBAQCjy6OBleSmGeRU 8 | 0KeWJ0aqVKo6Auuu2BFd/6saExBk7BiNXoYmM4o0GH2JCxTMoI2eqecZbgChLU6g 9 | MKVUKeIuzcp9Og5ZNwM1NDeCER2vFX2WIvJ/4Z4Iyn6GuMOTmPnN9jHTbiopbjm0 10 | FcuiVk+xJefxljA5sIqfRuEuD4NwBPYP8QodSzYTHbpG55MmvF+LMh/yDffTaGk6 11 | lXnflh56R53MpCoin2S1WiWDreu7tXvMcL8lwQ1RtZqTM3y+f0XD/7pIWtkaGurl 12 | +y4bMkZF5UmwBvYy2Tk7wd5Ch9orUNNQN3w4Biw2/yY+KMj7ZzsQ2ZliVSsFUQIO 13 | Jj7hWLTxAoGBAM+uvi/N4YgaJxa9N9dU4k1DphU1hisjzZq1PoFHCigZQBPQEsWY 14 | iu5r3XOYAWOiKYCxfFDPHJOUQOlHCqfHW3LQyvY9JttMCT+6MncpVPuEf1/+hvGp 15 | 4tPJ4NyPqYTA+CcngZBErBvi+QryLwguf6Se2Vzbf9KSR3vKZ+L2B8TbAoGBAPan 16 | 1IsE4mF9ycKL511GUh9BeZrV36zQMT1nUy9kwzgRAQdZr8zNncfL16V5Wd0OT/mL 17 | TsEHte5ah58Vs5SelGmNAruyBd902ao7/Pe+xfPLOZHEPMyXUU0TP2zh9ZdIhfro 18 | rkVsaT1E/2iav+JkxIFoNirkCjnH1/TFQJEISen1AoGBAK/uCmR6lovyA5zqq4w4 19 | 9v+Wx/F9huuyh7B/yrQ+1qbDRRnDkLNcloyESXNrl/mr3FaNg4788+s8koRKzwb0 20 | BU7M+rH/eZQZ5FfcxnVVSQ1L348VEYFUdbcNc/PDq0mvIkgg2ku5MMbqzidso1Td 21 | 9vkgK2fS9YQOsIl4G+sSmeAzAoGBAO1e6n63Pp2QDoD5Xrk3GYUW386QkOegnCJ5 22 | s2Zi1DS6uIC4YST5pCRJGckXldHVGkYPOMUvhHhUCzygB+i5DB7gI4c6dchsjaT0 23 | gihyIdLS+x46+j/yR72jDmDcvBrRIo8rKbuJ72WVZy7l7lATpcDb53UzbFva5Quc 24 | YNyyW1+ZAoGBAJScAQEcqV1jusjJlpXibdSG8Gu/iIuZKxbBM9X4xtRNHXRc+nmK 25 | 49qLy94+YiFoIx+Edbd1MVADe1+zCU6p7LZcv8zRzgmwi6YdIbbyOTzQyWaqsybL 26 | 2xTomW4GXfpMx32YVd0z19KDf8CV2sXPmmz69NXqQdAb+6vi0RN4d02n 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /terraform/serverb/serverb.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID/DCCAuSgAwIBAgIUZVnMqNCL5BLfHNHm5PHhFjaeUWIwDQYJKoZIhvcNAQEL 3 | BQAwejELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdlbGVzMQswCQYDVQQH 4 | EwJDQTEQMA4GA1UEChMHU3luYWRpYTENMAsGA1UECxMETkFUUzEnMCUGA1UEAxMe 5 | Q3VzdG9tIE5BVFMgTGF0ZW5jeSBUZXN0aW5nIENBMB4XDTE4MDgyNzIxMDAwMFoX 6 | DTIzMDgyNjIxMDAwMFowSDELMAkGA1UEBhMCVVMxFDASBgNVBAgTC0xvcyBBbmdl 7 | bGVzMQswCQYDVQQHEwJDQTEWMBQGA1UEAxMNTkFUUyBzZXJ2ZXIgQjCCASIwDQYJ 8 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMgaEi1+XUOwYEYxDu5FckdPV6L9OxOX 9 | vehkmXoDC/pLhQDYUrZRhvXsv3X++mCN1dSmDkZTZ90saFLWv5JuOdI1INsAFXh7 10 | I6rJufUkUFyhbmTr2wVRDDMBg6WYa3yeiIg2cDBBMYWqjruTikPn2Bpx09jIvTNc 11 | NN+HXYuzFQX5T0B5cqcd/HayrQrdiH2KI+0JrMznKjNjX+sptbwJYR8Rs4GmqMO3 12 | ks2ert7O+LJjnoh66rOO2Go9cGao4EdqSJeqqQLP7h1SEZVSt85POV/BHLI6Vq6J 13 | mIDK7z60XhGBQch3lsZoGxjF+pOPzkcunCBCl4/2/Y+i7M+ki4INuJcCAwEAAaOB 14 | qzCBqDAOBgNVHQ8BAf8EBAMCBaAwIwYDVR0lBBwwGgYEVR0lAAYIKwYBBQUHAwEG 15 | CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCzMABeDDFKI5cPLuPF5 16 | aX/mpRijMB8GA1UdIwQYMBaAFKl9v2eBqx93yxDmBaYwO2ju9gZBMCMGA1UdEQQc 17 | MBqCB3NlcnZlcmKCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEA 18 | K8DmcxIw/KtjzMTeGeJWzlVseXYRFjxSf2YKhzct7OsdK9YrDyjjiGYZcvDK/1cy 19 | obt/kWIbiYn3HRxSM8TwvRVZBt1F4Qqj6g30sc/r5ZAukd5hKOhcFfH+7uxpMt7l 20 | qm5HPndOZwLjFLebshpos37tKjO+HNHkr+Dc6j4JumVWl5kHozCEILliXlqsfUJ4 21 | GE3NcK95yCwQGAQna2EWLeAqnKRJalwrICaabUgR439iKJXoHuDkj4Rbb5/gsMNo 22 | Bujl8siw+f+huEJmAJm97nkhBd5ZXerbeXZcztM49P2UpxVABHqIyDGDNXiF1qci 23 | uR4U6pkbrvvtjrn/R6rxgw== 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /terraform/tls-scripts/config/ca-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "signing": { 3 | "default": { 4 | "expiry": "43800h" 5 | }, 6 | "profiles": { 7 | "server": { 8 | "expiry": "43800h", 9 | "usages": [ 10 | "any", 11 | "signing", 12 | "key encipherment", 13 | "server auth", 14 | "client auth" 15 | ] 16 | }, 17 | "client": { 18 | "expiry": "43800h", 19 | "usages": [ 20 | "any", 21 | "signing", 22 | "key encipherment", 23 | "client auth" 24 | ] 25 | }, 26 | "route": { 27 | "expiry": "43800h", 28 | "usages": [ 29 | "any", 30 | "signing", 31 | "key encipherment", 32 | "server auth", 33 | "client auth" 34 | ] 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /terraform/tls-scripts/config/ca-csr.json: -------------------------------------------------------------------------------- 1 | { 2 | "CN": "Custom NATS Latency Testing CA", 3 | "key": { 4 | "algo": "rsa", 5 | "size": 2048 6 | }, 7 | "names": [ 8 | { 9 | "C": "US", 10 | "L": "CA", 11 | "O": "Synadia", 12 | "ST": "Los Angeles", 13 | "OU": "NATS" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /terraform/tls-scripts/config/client.json: -------------------------------------------------------------------------------- 1 | { 2 | "CN": "Client", 3 | "hosts": [ 4 | "client", 5 | "localhost", 6 | "127.0.0.1" 7 | ], 8 | "key": { 9 | "algo": "rsa", 10 | "size": 2048 11 | }, 12 | "names": [ 13 | { 14 | "C": "US", 15 | "L": "CA", 16 | "ST": "Los Angeles" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /terraform/tls-scripts/config/servera.json: -------------------------------------------------------------------------------- 1 | { 2 | "CN": "NATS server A", 3 | "hosts": [ 4 | "servera", 5 | "localhost", 6 | "127.0.0.1" 7 | ], 8 | "key": { 9 | "algo": "rsa", 10 | "size": 2048 11 | }, 12 | "names": [ 13 | { 14 | "C": "US", 15 | "L": "CA", 16 | "ST": "Los Angeles" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /terraform/tls-scripts/config/serverb.json: -------------------------------------------------------------------------------- 1 | { 2 | "CN": "NATS server B", 3 | "hosts": [ 4 | "serverb", 5 | "localhost", 6 | "127.0.0.1" 7 | ], 8 | "key": { 9 | "algo": "rsa", 10 | "size": 2048 11 | }, 12 | "names": [ 13 | { 14 | "C": "US", 15 | "L": "CA", 16 | "ST": "Los Angeles" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /terraform/tls-scripts/gencerts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # cfssl must be installed. 5 | # 6 | cfssl gencert -initca config/ca-csr.json | cfssljson -bare ca - 7 | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=config/ca-config.json -profile=server config/servera.json | cfssljson -bare servera 8 | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=config/ca-config.json -profile=server config/serverb.json | cfssljson -bare serverb 9 | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=config/ca-config.json -profile=client config/client.json | cfssljson -bare client 10 | 11 | # Copy files 12 | cp ca.pem ../servera/ 13 | mv servera-key.pem ../servera 14 | mv servera.pem ../servera 15 | 16 | cp ca.pem ../serverb 17 | mv serverb-key.pem ../serverb 18 | mv serverb.pem ../serverb 19 | 20 | cp ca.pem ../client 21 | mv client-key.pem ../client 22 | mv client.pem ../client 23 | 24 | rm ca.pem ca-key.pem *.csr 25 | 26 | --------------------------------------------------------------------------------