|
| 1 | +//go:build !slim |
| 2 | + |
| 3 | +package cli |
| 4 | + |
| 5 | +import ( |
| 6 | +"fmt" |
| 7 | + |
| 8 | +"github.com/prometheus/client_golang/prometheus" |
| 9 | +"golang.org/x/xerrors" |
| 10 | + |
| 11 | +"cdr.dev/slog" |
| 12 | +"cdr.dev/slog/sloggers/sloghuman" |
| 13 | + |
| 14 | +"github.com/coder/coder/v2/scaletest/dynamicparameters" |
| 15 | +"github.com/coder/coder/v2/scaletest/harness" |
| 16 | +"github.com/coder/serpent" |
| 17 | +) |
| 18 | + |
| 19 | +const ( |
| 20 | +dynamicParametersTestName="dynamic-parameters" |
| 21 | +) |
| 22 | + |
| 23 | +func (r*RootCmd)scaletestDynamicParameters()*serpent.Command { |
| 24 | +vartemplateNamestring |
| 25 | +varnumEvalsint64 |
| 26 | +orgContext:=NewOrganizationContext() |
| 27 | +output:=&scaletestOutputFlags{} |
| 28 | + |
| 29 | +cmd:=&serpent.Command{ |
| 30 | +Use:"dynamic-parameters", |
| 31 | +Short:"Generates load on the Coder server evaluating dynamic parameters", |
| 32 | +Long:`It is recommended that all rate limits are disabled on the server before running this scaletest. This test generates many login events which will be rate limited against the (most likely single) IP.`, |
| 33 | +Handler:func(inv*serpent.Invocation)error { |
| 34 | +ctx:=inv.Context() |
| 35 | + |
| 36 | +outputs,err:=output.parse() |
| 37 | +iferr!=nil { |
| 38 | +returnxerrors.Errorf("could not parse --output flags") |
| 39 | +} |
| 40 | + |
| 41 | +client,err:=r.InitClient(inv) |
| 42 | +iferr!=nil { |
| 43 | +returnerr |
| 44 | +} |
| 45 | +iftemplateName=="" { |
| 46 | +returnxerrors.Errorf("template cannot be empty") |
| 47 | +} |
| 48 | + |
| 49 | +org,err:=orgContext.Selected(inv,client) |
| 50 | +iferr!=nil { |
| 51 | +returnerr |
| 52 | +} |
| 53 | + |
| 54 | +logger:=slog.Make(sloghuman.Sink(inv.Stdout)).Leveled(slog.LevelDebug) |
| 55 | +partitions,err:=dynamicparameters.SetupPartitions(ctx,client,org.ID,templateName,numEvals,logger) |
| 56 | +iferr!=nil { |
| 57 | +returnxerrors.Errorf("setup dynamic parameters partitions: %w",err) |
| 58 | +} |
| 59 | + |
| 60 | +th:=harness.NewTestHarness(harness.ConcurrentExecutionStrategy{}, harness.ConcurrentExecutionStrategy{}) |
| 61 | +reg:=prometheus.NewRegistry() |
| 62 | +metrics:=dynamicparameters.NewMetrics(reg,"concurrent_evaluations") |
| 63 | + |
| 64 | +fori,part:=rangepartitions { |
| 65 | +forj:=rangepart.ConcurrentEvaluations { |
| 66 | +cfg:= dynamicparameters.Config{ |
| 67 | +TemplateVersion:part.TemplateVersion.ID, |
| 68 | +Metrics:metrics, |
| 69 | +MetricLabelValues: []string{fmt.Sprintf("%d",part.ConcurrentEvaluations)}, |
| 70 | +} |
| 71 | +runner:=dynamicparameters.NewRunner(client,cfg) |
| 72 | +th.AddRun(dynamicParametersTestName,fmt.Sprintf("%d/%d",j,i),runner) |
| 73 | +} |
| 74 | +} |
| 75 | + |
| 76 | +err=th.Run(ctx) |
| 77 | +iferr!=nil { |
| 78 | +returnxerrors.Errorf("run test harness: %w",err) |
| 79 | +} |
| 80 | + |
| 81 | +res:=th.Results() |
| 82 | +for_,o:=rangeoutputs { |
| 83 | +err=o.write(res,inv.Stdout) |
| 84 | +iferr!=nil { |
| 85 | +returnxerrors.Errorf("write output %q to %q: %w",o.format,o.path,err) |
| 86 | +} |
| 87 | +} |
| 88 | + |
| 89 | +returnnil |
| 90 | +}, |
| 91 | +} |
| 92 | + |
| 93 | +cmd.Options= serpent.OptionSet{ |
| 94 | +{ |
| 95 | +Flag:"template", |
| 96 | +Description:"Name of the template to use. If it does not exist, it will be created.", |
| 97 | +Default:"scaletest-dynamic-parameters", |
| 98 | +Value:serpent.StringOf(&templateName), |
| 99 | +}, |
| 100 | +{ |
| 101 | +Flag:"concurrent-evaluations", |
| 102 | +Description:"Number of concurrent dynamic parameter evaluations to perform.", |
| 103 | +Default:"100", |
| 104 | +Value:serpent.Int64Of(&numEvals), |
| 105 | +}, |
| 106 | +} |
| 107 | +orgContext.AttachOptions(cmd) |
| 108 | +output.attach(&cmd.Options) |
| 109 | +returncmd |
| 110 | +} |