diff --git a/README.md b/README.md index 911a532d21..346c272a75 100644 --- a/README.md +++ b/README.md @@ -150,15 +150,16 @@ benchmarks: # Benchmark a container named nginx using POST HTTP verb using http://localhost:port/bozo URL and headers. concurrency: 1 requests: 10000 - path: /bozo - method: POST - body: - {"fred":"blee"} - header: - Accept: - - text/html - Content-Type: - - application/json + http: + path: /bozo + method: POST + body: + {"fred":"blee"} + header: + Accept: + - text/html + Content-Type: + - application/json services: # Similary you can Benchmark an HTTP service exposed either via nodeport, loadbalancer types. # Service ID is ns/svc-name @@ -167,11 +168,12 @@ benchmarks: concurrency: 5 # Issues a total of 500 requests requests: 500 - method: GET - # This setting will depend on whether service is nodeport or loadbalancer. Nodeport may require vendor port tuneling setting. - # Set this to a node if nodeport or LB if applicable. IP or dns name. - host: 10.11.13.14 - path: /bumblebeetuna + http: + method: GET + # This setting will depend on whether service is nodeport or loadbalancer. Nodeport may require vendor port tuneling setting. + # Set this to a node if nodeport or LB if applicable. IP or dns name. + host: 10.11.13.14 + path: /bumblebeetuna auth: user: jean-baptiste-emmanuel password: Zorg! diff --git a/internal/config/bench.go b/internal/config/bench.go index b7e114d2b2..a224f17caa 100644 --- a/internal/config/bench.go +++ b/internal/config/bench.go @@ -37,18 +37,23 @@ type ( N int `yaml:"requests"` } - // BenchConfig represents a service benchmark. - BenchConfig struct { - C int `yaml:"concurrency"` - N int `yaml:"requests"` + // HTTP represents an http request. + HTTP struct { Method string `yaml:"method"` Host string `yaml:"host"` Path string `yaml:"path"` HTTP2 bool `yaml:"http2"` Body string `yaml:"body"` - Auth Auth `yaml:"auth"` Headers http.Header `yaml:"headers"` - Name string + } + + // BenchConfig represents a service benchmark. + BenchConfig struct { + C int `yaml:"concurrency"` + N int `yaml:"requests"` + Auth Auth `yaml:"auth"` + HTTP HTTP `yaml:"http"` + Name string } ) diff --git a/internal/config/bench_test.go b/internal/config/bench_test.go index 2c9536d861..bd15f6596f 100644 --- a/internal/config/bench_test.go +++ b/internal/config/bench_test.go @@ -104,13 +104,13 @@ func TestBenchServiceLoad(t *testing.T) { svc := b.Benchmarks.Services[u.key] assert.Equal(t, u.c, svc.C) assert.Equal(t, u.n, svc.N) - assert.Equal(t, u.method, svc.Method) - assert.Equal(t, u.host, svc.Host) - assert.Equal(t, u.path, svc.Path) - assert.Equal(t, u.http2, svc.HTTP2) - assert.Equal(t, u.body, svc.Body) + assert.Equal(t, u.method, svc.HTTP.Method) + assert.Equal(t, u.host, svc.HTTP.Host) + assert.Equal(t, u.path, svc.HTTP.Path) + assert.Equal(t, u.http2, svc.HTTP.HTTP2) + assert.Equal(t, u.body, svc.HTTP.Body) assert.Equal(t, u.auth, svc.Auth) - assert.Equal(t, u.headers, svc.Headers) + assert.Equal(t, u.headers, svc.HTTP.Headers) }) } } @@ -174,13 +174,13 @@ func TestBenchContainerLoad(t *testing.T) { co := b.Benchmarks.Containers[u.key] assert.Equal(t, u.c, co.C) assert.Equal(t, u.n, co.N) - assert.Equal(t, u.method, co.Method) - assert.Equal(t, u.host, co.Host) - assert.Equal(t, u.path, co.Path) - assert.Equal(t, u.http2, co.HTTP2) - assert.Equal(t, u.body, co.Body) + assert.Equal(t, u.method, co.HTTP.Method) + assert.Equal(t, u.host, co.HTTP.Host) + assert.Equal(t, u.path, co.HTTP.Path) + assert.Equal(t, u.http2, co.HTTP.HTTP2) + assert.Equal(t, u.body, co.HTTP.Body) assert.Equal(t, u.auth, co.Auth) - assert.Equal(t, u.headers, co.Headers) + assert.Equal(t, u.headers, co.HTTP.Headers) }) } } diff --git a/internal/config/test_assets/b_containers.yml b/internal/config/test_assets/b_containers.yml index 88136be180..5400db191a 100644 --- a/internal/config/test_assets/b_containers.yml +++ b/internal/config/test_assets/b_containers.yml @@ -6,69 +6,73 @@ benchmarks: c1: concurrency: 2 requests: 1000 - method: GET - http2: true - host: 10.10.10.10 - path: /duh - body: |- - {"fred": "blee"} + http: + method: GET + http2: true + host: 10.10.10.10 + path: /duh + body: |- + {"fred": "blee"} + headers: + Accept: + - text/html + Content-Type: + - application/json auth: user: "fred" password: "blee" - headers: - Accept: - - text/html - Content-Type: - - application/json c2: concurrency: 10 requests: 1500 - method: POST - http2: false - host: 20.20.20.20 - path: /fred - body: |- - {"fred": "blee"} + http: + method: POST + http2: false + host: 20.20.20.20 + path: /fred + body: |- + {"fred": "blee"} + headers: + Accept: + - text/html + Content-Type: + - application/json auth: user: "fred" password: "blee" - headers: - Accept: - - text/html - Content-Type: - - application/json services: default/nginx: concurrency: 2 requests: 1000 - method: GET - http2: true - host: 10.10.10.10 - path: / - body: |- - {"fred": "blee"} + http: + method: GET + http2: true + host: 10.10.10.10 + path: / + body: |- + {"fred": "blee"} + headers: + Accept: + - text/html + Content-Type: + - application/json auth: user: "fred" password: "blee" - headers: - Accept: - - text/html - Content-Type: - - application/json blee/fred: concurrency: 10 requests: 1500 - method: POST - http2: false - host: 20.20.20.20 - path: /blee - body: |- - {"fred": "blee"} - auth: - user: "fred" - password: "blee" - headers: - Accept: - - text/html - Content-Type: - - application/json + http: + method: POST + http2: false + host: 20.20.20.20 + path: /blee + body: |- + {"fred": "blee"} + headers: + Accept: + - text/html + Content-Type: + - application/json + auth: + user: "fred" + password: "blee" \ No newline at end of file diff --git a/internal/config/test_assets/b_containers_1.yml b/internal/config/test_assets/b_containers_1.yml index 03fd67eb05..fb9726e552 100644 --- a/internal/config/test_assets/b_containers_1.yml +++ b/internal/config/test_assets/b_containers_1.yml @@ -6,69 +6,73 @@ benchmarks: c1: concurrency: 2 requests: 1000 - method: GET - http2: true - host: 10.10.10.10 - path: /duh - body: |- - {"fred": "blee"} - auth: - user: "fred" - password: "blee" + http: + method: GET + http2: true + host: 10.10.10.10 + path: /duh + body: |- + {"fred": "blee"} headers: Accept: - text/html Content-Type: - application/json + auth: + user: "fred" + password: "blee" c2: concurrency: 10 requests: 1500 - method: POST - http2: false - host: 20.20.20.20 - path: /fred - body: |- - {"fred": "blee"} + http: + method: POST + http2: false + host: 20.20.20.20 + path: /fred + body: |- + {"fred": "blee"} + headers: + Accept: + - text/html + Content-Type: + - application/json auth: user: "fred" password: "blee" - headers: - Accept: - - text/html - Content-Type: - - application/json services: default/nginx: concurrency: 2 requests: 1000 - method: GET - http2: true - host: 10.10.10.10 - path: / - body: |- - {"fred": "blee"} + http: + method: GET + http2: true + host: 10.10.10.10 + path: / + body: |- + {"fred": "blee"} + headers: + Accept: + - text/html + Content-Type: + - application/json auth: user: "fred" password: "blee" - headers: - Accept: - - text/html - Content-Type: - - application/json blee/fred: concurrency: 10 requests: 1500 - method: POST - http2: false - host: 20.20.20.20 - path: /blee - body: |- - {"fred": "blee"} + http: + method: POST + http2: false + host: 20.20.20.20 + path: /blee + body: |- + {"fred": "blee"} + headers: + Accept: + - text/html + Content-Type: + - application/json auth: user: "fred" password: "blee" - headers: - Accept: - - text/html - Content-Type: - - application/json diff --git a/internal/config/test_assets/b_good.yml b/internal/config/test_assets/b_good.yml index e487f64ec8..d418453c69 100644 --- a/internal/config/test_assets/b_good.yml +++ b/internal/config/test_assets/b_good.yml @@ -6,34 +6,36 @@ benchmarks: default/nginx: concurrency: 2 requests: 1000 - method: GET - http2: true - host: 10.10.10.10 - path: / - body: |- - {"fred": "blee"} + http: + method: GET + http2: true + host: 10.10.10.10 + path: / + body: |- + {"fred": "blee"} + headers: + Accept: + - text/html + Content-Type: + - application/json auth: user: "fred" password: "blee" - headers: - Accept: - - text/html - Content-Type: - - application/json blee/fred: concurrency: 10 requests: 1500 - method: POST - http2: false - host: 20.20.20.20 - path: /zorg - body: |- - {"fred": "blee"} + http: + method: POST + http2: false + host: 20.20.20.20 + path: /zorg + body: |- + {"fred": "blee"} + headers: + Accept: + - text/html + Content-Type: + - application/json auth: user: "fred" password: "blee" - headers: - Accept: - - text/html - Content-Type: - - application/json diff --git a/internal/config/test_assets/b_toast.yml b/internal/config/test_assets/b_toast.yml index 1d0fa68d07..106543cb46 100644 --- a/internal/config/test_assets/b_toast.yml +++ b/internal/config/test_assets/b_toast.yml @@ -2,15 +2,16 @@ benchmarks: service: - default/nginx: concurrency: 1 - requests: 100 - http2: true - method: GET - url: http://35.224.16.201/ - body: |- - {"fred": "blee"} + http: + requests: 100 + http2: true + method: GET + url: http://35.224.16.201/ + body: |- + {"fred": "blee"} + headers: + - "Accept: text/html" + - "Content-Type: application/json" auth: user: "fred" - password: "blee" - headers: - - "Accept: text/html" - - "Content-Type: application/json" \ No newline at end of file + password: "blee" \ No newline at end of file diff --git a/internal/resource/ep.go b/internal/resource/ep.go index 4323035c08..fdb6607f28 100644 --- a/internal/resource/ep.go +++ b/internal/resource/ep.go @@ -102,17 +102,18 @@ func (r *Endpoints) toEPs(ss []v1.EndpointSubset) string { } for _, a := range s.Addresses { - if len(a.IP) != 0 { - if len(pp) == 0 { - aa = append(aa, a.IP) - } else { - add := a.IP + ":" + strings.Join(pp, ",") - if len(pp) > max { - add = a.IP + ":" + strings.Join(pp[:max], ",") + "..." - } - aa = append(aa, add) - } + if len(a.IP) == 0 { + continue } + if len(pp) == 0 { + aa = append(aa, a.IP) + continue + } + add := a.IP + ":" + strings.Join(pp, ",") + if len(pp) > max { + add = a.IP + ":" + strings.Join(pp[:max], ",") + "..." + } + aa = append(aa, add) } } diff --git a/internal/views/benchmark.go b/internal/views/benchmark.go index e0bd8d5a8d..c2ab9f4830 100644 --- a/internal/views/benchmark.go +++ b/internal/views/benchmark.go @@ -36,7 +36,7 @@ func newBenchmark(base string, cfg config.BenchConfig) (*benchmark, error) { } func (b *benchmark) init(base string) error { - req, err := http.NewRequest(b.config.Method, base, nil) + req, err := http.NewRequest(b.config.HTTP.Method, base, nil) if err != nil { return err } @@ -45,7 +45,7 @@ func (b *benchmark) init(base string) error { req.SetBasicAuth(b.config.Auth.User, b.config.Auth.Password) } - req.Header = b.config.Headers + req.Header = b.config.HTTP.Headers ua := req.UserAgent() if ua == "" { ua = k9sUA @@ -59,10 +59,10 @@ func (b *benchmark) init(base string) error { b.worker = &requester.Work{ Request: req, - RequestBody: []byte(b.config.Body), + RequestBody: []byte(b.config.HTTP.Body), N: b.config.N, C: b.config.C, - H2: b.config.HTTP2, + H2: b.config.HTTP.HTTP2, Output: "", } diff --git a/internal/views/command.go b/internal/views/command.go index 9e3a424798..5f1e3f5ecc 100644 --- a/internal/views/command.go +++ b/internal/views/command.go @@ -48,9 +48,7 @@ func (c *command) defaultCmd() { var policyMatcher = regexp.MustCompile(`\Apol\s([u|g|s]):([\w-:]+)\b`) -// Exec the command by showing associated display. -func (c *command) run(cmd string) bool { - var v resourceViewer +func (c *command) isStdCmd(cmd string) bool { switch { case cmd == "q", cmd == "quit": c.app.BailOut() @@ -67,37 +65,48 @@ func (c *command) run(cmd string) bool { c.app.inject(newPolicyView(c.app, tokens[0][1], tokens[0][2])) return true } - default: - cmds := make(map[string]resCmd, 30) - resourceViews(c.app.conn(), cmds) - if res, ok := cmds[cmd]; ok { - var r resource.List - if res.listFn != nil { - r = res.listFn(c.app.conn(), resource.DefaultNamespace) - } - v = res.viewFn(res.title, c.app, r) - if res.colorerFn != nil { - v.setColorerFn(res.colorerFn) - } - if res.enterFn != nil { - v.setEnterFn(res.enterFn) - } - if res.decorateFn != nil { - v.setDecorateFn(res.decorateFn) - } - const fmat = "Viewing resource %s..." - c.app.flash().infof(fmat, res.title) - log.Debug().Msgf("Running command %s", cmd) - c.exec(cmd, v) - return true - } } + return false +} + +func (c *command) isAliasCmd(cmd string) bool { cmds := make(map[string]resCmd, 30) - allCRDs(c.app.conn(), cmds) + resourceViews(c.app.conn(), cmds) res, ok := cmds[cmd] if !ok { - c.app.flash().warnf("Huh? `%s` command not found", cmd) + return false + } + + var r resource.List + if res.listFn != nil { + r = res.listFn(c.app.conn(), resource.DefaultNamespace) + } + + v := res.viewFn(res.title, c.app, r) + if res.colorerFn != nil { + v.setColorerFn(res.colorerFn) + } + if res.enterFn != nil { + v.setEnterFn(res.enterFn) + } + if res.decorateFn != nil { + v.setDecorateFn(res.decorateFn) + } + + const fmat = "Viewing resource %s..." + c.app.flash().infof(fmat, res.title) + log.Debug().Msgf("Running command %s", cmd) + c.exec(cmd, v) + + return true +} + +func (c *command) isCRDCmd(cmd string) bool { + crds := map[string]resCmd{} + allCRDs(c.app.conn(), crds) + res, ok := crds[cmd] + if !ok { return false } @@ -105,7 +114,7 @@ func (c *command) run(cmd string) bool { if name == "" { name = res.singular } - v = newResourceView( + v := newResourceView( res.title, c.app, resource.NewCustomList(c.app.conn(), "", res.api, res.version, name), @@ -116,6 +125,24 @@ func (c *command) run(cmd string) bool { return true } +// Exec the command by showing associated display. +func (c *command) run(cmd string) bool { + if c.isStdCmd(cmd) { + return true + } + + if c.isAliasCmd(cmd) { + return true + } + + if c.isCRDCmd(cmd) { + return true + } + + c.app.flash().warnf("Huh? `%s` command not found", cmd) + return false +} + func (c *command) exec(cmd string, v igniter) { if v == nil { return diff --git a/internal/views/forward.go b/internal/views/forward.go index f5390c765b..4f09586a41 100644 --- a/internal/views/forward.go +++ b/internal/views/forward.go @@ -144,10 +144,12 @@ func (v *forwardView) benchCmd(evt *tcell.EventKey) *tcell.EventKey { r, _ := tv.GetSelection() cfg := config.BenchConfig{ - C: config.DefaultC, - N: config.DefaultN, - Method: config.DefaultMethod, - Path: "/", + C: config.DefaultC, + N: config.DefaultN, + HTTP: config.HTTP{ + Method: config.DefaultMethod, + Path: "/", + }, } co := strings.TrimSpace(tv.GetCell(r, 2).Text) if b, ok := v.app.bench.Benchmarks.Containers[containerID(sel, co)]; ok { diff --git a/internal/views/helpers.go b/internal/views/helpers.go index 3724913632..389e6f84bb 100644 --- a/internal/views/helpers.go +++ b/internal/views/helpers.go @@ -51,13 +51,13 @@ func containerID(path, co string) string { // UrlFor computes fq url for a given benchmark configuration. func urlFor(cfg config.BenchConfig, co, port string) string { host := "localhost" - if cfg.Host != "" { - host = cfg.Host + if cfg.HTTP.Host != "" { + host = cfg.HTTP.Host } path := "/" - if cfg.Path != "" { - path = cfg.Path + if cfg.HTTP.Path != "" { + path = cfg.HTTP.Path } return "http://" + host + ":" + port + path diff --git a/internal/views/helpers_test.go b/internal/views/helpers_test.go index 88182dfdfa..37ef40c5a5 100644 --- a/internal/views/helpers_test.go +++ b/internal/views/helpers_test.go @@ -82,10 +82,25 @@ func TestUrlFor(t *testing.T) { config.BenchConfig{}, "c1", "9000", "http://localhost:9000/", }, "path": { - config.BenchConfig{Path: "/fred/blee"}, "c1", "9000", "http://localhost:9000/fred/blee", + config.BenchConfig{ + HTTP: config.HTTP{ + Path: "/fred/blee", + }, + }, + "c1", + "9000", + "http://localhost:9000/fred/blee", }, "host/path": { - config.BenchConfig{Host: "zorg", Path: "/fred/blee"}, "c1", "9000", "http://zorg:9000/fred/blee", + config.BenchConfig{ + HTTP: config.HTTP{ + Host: "zorg", + Path: "/fred/blee", + }, + }, + "c1", + "9000", + "http://zorg:9000/fred/blee", }, } diff --git a/internal/views/svc.go b/internal/views/svc.go index fc5fbeb20f..775b7c07c8 100644 --- a/internal/views/svc.go +++ b/internal/views/svc.go @@ -190,7 +190,7 @@ func (v *svcView) benchCmd(evt *tcell.EventKey) *tcell.EventKey { func (v *svcView) runBenchmark(port string, cfg config.BenchConfig) error { var err error - base := "http://" + cfg.Host + ":" + port + cfg.Path + base := "http://" + cfg.HTTP.Host + ":" + port + cfg.HTTP.Path if v.bench, err = newBenchmark(base, cfg); err != nil { return err }