github.com/letsencrypt/boulder@v0.20251208.0/test/load-generator/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "encoding/json" 6 "flag" 7 "fmt" 8 "os" 9 "strconv" 10 "strings" 11 "time" 12 13 "github.com/letsencrypt/boulder/cmd" 14 ) 15 16 type Config struct { 17 // Execution plan parameters 18 Plan struct { 19 Actions []string // things to do 20 Rate int64 // requests / s 21 RateDelta string // requests / s^2 22 Runtime string // how long to run for 23 } 24 ExternalState string // path to file to load/save registrations etc to/from 25 DontSaveState bool // don't save changes to external state 26 DirectoryURL string // ACME server directory URL 27 DomainBase string // base domain name to create authorizations for 28 HTTPOneAddrs []string // addresses to listen for http-01 validation requests on 29 TLSALPNOneAddrs []string // addresses to listen for tls-alpn-01 validation requests on 30 DNSAddrs []string // addresses to listen for DNS requests on 31 FakeDNS string // IPv6 address to use for all DNS A requests 32 RealIP string // value of the Real-IP header to use when bypassing CDN 33 RegEmail string // email to use in registrations 34 Results string // path to save metrics to 35 MaxRegs int // maximum number of registrations to create 36 MaxNamesPerCert int // maximum number of names on one certificate/order 37 ChallengeStrategy string // challenge selection strategy ("random", "http-01", "dns-01", "tls-alpn-01") 38 RevokeChance float32 // chance of revoking certificate after issuance, between 0.0 and 1.0 39 } 40 41 func main() { 42 configPath := flag.String("config", "", "Path to configuration file for load-generator") 43 resultsPath := flag.String("results", "", "Path to latency results file") 44 rateArg := flag.Int("rate", 0, "") 45 runtimeArg := flag.String("runtime", "", "") 46 deltaArg := flag.String("delta", "", "") 47 flag.Parse() 48 49 if *configPath == "" { 50 fmt.Fprintf(os.Stderr, "-config argument must not be empty\n") 51 os.Exit(1) 52 } 53 54 configBytes, err := os.ReadFile(*configPath) 55 if err != nil { 56 fmt.Fprintf(os.Stderr, "Failed to read load-generator config file %q: %s\n", *configPath, err) 57 os.Exit(1) 58 } 59 var config Config 60 err = json.Unmarshal(configBytes, &config) 61 if err != nil { 62 fmt.Fprintf(os.Stderr, "Failed to parse load-generator config file: %s\n", err) 63 os.Exit(1) 64 } 65 66 if *resultsPath != "" { 67 config.Results = *resultsPath 68 } 69 if *rateArg != 0 { 70 config.Plan.Rate = int64(*rateArg) 71 } 72 if *runtimeArg != "" { 73 config.Plan.Runtime = *runtimeArg 74 } 75 if *deltaArg != "" { 76 config.Plan.RateDelta = *deltaArg 77 } 78 79 s, err := New( 80 config.DirectoryURL, 81 config.DomainBase, 82 config.RealIP, 83 config.MaxRegs, 84 config.MaxNamesPerCert, 85 config.Results, 86 config.RegEmail, 87 config.Plan.Actions, 88 config.ChallengeStrategy, 89 config.RevokeChance, 90 ) 91 cmd.FailOnError(err, "Failed to create load generator") 92 93 if config.ExternalState != "" { 94 err = s.Restore(config.ExternalState) 95 cmd.FailOnError(err, "Failed to load registration snapshot") 96 } 97 98 runtime, err := time.ParseDuration(config.Plan.Runtime) 99 cmd.FailOnError(err, "Failed to parse plan runtime") 100 101 var delta *RateDelta 102 if config.Plan.RateDelta != "" { 103 parts := strings.Split(config.Plan.RateDelta, "/") 104 if len(parts) != 2 { 105 fmt.Fprintf(os.Stderr, "RateDelta is malformed") 106 os.Exit(1) 107 } 108 rate, err := strconv.Atoi(parts[0]) 109 cmd.FailOnError(err, "Failed to parse increase portion of RateDelta") 110 period, err := time.ParseDuration(parts[1]) 111 cmd.FailOnError(err, "Failed to parse period portion of RateDelta") 112 delta = &RateDelta{Inc: int64(rate), Period: period} 113 } 114 115 if len(config.HTTPOneAddrs) == 0 && 116 len(config.TLSALPNOneAddrs) == 0 && 117 len(config.DNSAddrs) == 0 { 118 cmd.Fail("There must be at least one bind address in " + 119 "HTTPOneAddrs, TLSALPNOneAddrs or DNSAddrs\n") 120 } 121 122 ctx, cancel := context.WithCancel(context.Background()) 123 go cmd.CatchSignals(cancel) 124 125 err = s.Run( 126 ctx, 127 config.HTTPOneAddrs, 128 config.TLSALPNOneAddrs, 129 config.DNSAddrs, 130 config.FakeDNS, 131 Plan{ 132 Runtime: runtime, 133 Rate: config.Plan.Rate, 134 Delta: delta, 135 }) 136 cmd.FailOnError(err, "Failed to run load generator") 137 138 if config.ExternalState != "" && !config.DontSaveState { 139 err = s.Snapshot(config.ExternalState) 140 cmd.FailOnError(err, "Failed to save registration snapshot") 141 } 142 143 fmt.Println("[+] All done, bye bye ^_^") 144 }