Skip to content

Commit

Permalink
make cli use /api/endpoints (#121)
Browse files Browse the repository at this point in the history
make cli use /api/endpoints instead of local static configuration
  • Loading branch information
kkr16 authored Oct 14, 2022
1 parent 89584b3 commit 0f9908c
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 47 deletions.
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@ Note: This is not an official Google product.
gcping [options...]
Options:
-n Number of requests to be made to each region.
By default 10; can't be negative.
-c Max number of requests to be made at any time.
By default 10; can't be negative or zero.
-r Report latency for an individual region.
-t Timeout. By default, no timeout.
Examples: "500ms", "1s", "1s500ms".
-top If true, only the top (non-global) region is printed.
-csv CSV output; disables verbose output.
-v Verbose output.
-n Number of requests to be made to each region.
By default 10; can't be negative.
-c Max number of requests to be made at any time.
By default 10; can't be negative or zero.
-r Report latency for an individual region.
-t Timeout. By default, no timeout.
Examples: "500ms", "1s", "1s500ms".
-top If true, only the top (non-global) region is printed.
-csv-cum If true, cumulative value is printed in CSV; disables default report.
-url URL of endpoint list. Default is https://global.gcping.com/api/endpoints
-csv CSV output; disables verbose output.
-v Verbose output.
Need a website version? See gcping.com
```
Expand Down
41 changes: 40 additions & 1 deletion internal/config/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,56 @@

package config

import (
"context"
"encoding/json"
"fmt"
"net/http"
)

// Endpoint represents a Cloud Run service deploy in a particular region.
type Endpoint struct {
// URL is the HTTPS URL of the service
URL string
// Region is the programmatic name of the region where the endpoint is
// deloyed, e.g., us-central1.
// deployed, e.g., us-central1.
Region string
// RegionName is the geographic name of the region, e.g., Iowa.
RegionName string
}

// EndpointsFromServer is used by the cli to generate an Endpoint map
// using json served by the gcping endpoints.
func EndpointsFromServer(ctx context.Context, endpointsURL string) (map[string]Endpoint, error) {

req, err := http.NewRequestWithContext(
ctx,
http.MethodGet,
endpointsURL,
nil,
)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%v %s", resp.Status, endpointsURL)
}

e := make(map[string]Endpoint)
decoder := json.NewDecoder(resp.Body)
if err := decoder.Decode(&e); err != nil {
return e, err
}

return e, err
}

// AllEndpoints associates a region name with its Cloud Run Endpoint.
var AllEndpoints = map[string]Endpoint{
"global": {
Expand Down
41 changes: 28 additions & 13 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package main

import (
"context"
"flag"
"fmt"
"net/http"
Expand All @@ -26,14 +27,15 @@ import (
)

var (
top bool
number int // number of requests for each region
concurrency int
timeout time.Duration
csv bool
csvCum bool
verbose bool
region string
top bool
number int // number of requests for each region
concurrency int
timeout time.Duration
csv bool
csvCum bool
verbose bool
region string
endpointsURL string
// TODO(jbd): Add payload options such as body size.

client *http.Client // TODO(jbd): One client per worker?
Expand All @@ -48,10 +50,22 @@ func main() {
flag.BoolVar(&csv, "csv", false, "")
flag.BoolVar(&csvCum, "csv-cum", false, "")
flag.StringVar(&region, "r", "", "")
flag.StringVar(&endpointsURL, "url", "https://global.gcping.com/api/endpoints", "")

flag.Usage = usage
flag.Parse()

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

// Fetch and cache endpoint map in memory for the duration of the
// process.
endpoints, err := config.EndpointsFromServer(ctx, endpointsURL)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

if number < 0 || concurrency <= 0 {
usage()
}
Expand All @@ -60,7 +74,7 @@ func main() {
}

if region != "" {
if _, found := config.AllEndpoints[region]; !found {
if _, found := endpoints[region]; !found {
fmt.Printf("region %q is not supported or does not exist\n", region)
os.Exit(1)
}
Expand All @@ -75,13 +89,13 @@ func main() {

switch {
case region != "":
w.reportRegion(region)
w.reportRegion(endpoints, region)
case top:
w.reportTop()
w.reportTop(endpoints)
case csvCum:
w.reportCSV()
w.reportCSV(endpoints)
default:
w.reportAll()
w.reportAll(endpoints)
}
}

Expand All @@ -102,6 +116,7 @@ Options:
Examples: "500ms", "1s", "1s500ms".
-top If true, only the top (non-global) region is printed.
-csv-cum If true, cumulative value is printed in CSV; disables default report.
-url URL of endpoint list. Default is https://global.gcping.com/api/endpoints
-csv CSV output; disables verbose output.
-v Verbose output.
Expand Down
43 changes: 21 additions & 22 deletions worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ func (w *worker) start() {
}
}

func (w *worker) sortOutput() []output {
func (w *worker) sortOutput(em map[string]config.Endpoint) []output {
m := make(map[string]output)
for i := 0; i < w.size(region); i++ {
for i := 0; i < w.size(em, region); i++ {
o := <-w.outputs

a := m[o.region]
Expand All @@ -133,17 +133,17 @@ func (w *worker) sortOutput() []output {
return all
}

func (w *worker) reportAll() {
func (w *worker) reportAll(em map[string]config.Endpoint) {
w.inputs = make(chan input, concurrency)
w.outputs = make(chan output, w.size(region))
w.outputs = make(chan output, w.size(em, region))
for i := 0; i < number; i++ {
for r, e := range config.AllEndpoints {
for r, e := range em {
w.inputs <- input{region: r, endpoint: e.URL}
}
}
close(w.inputs)

sorted := w.sortOutput()
sorted := w.sortOutput(em)
tr := tabwriter.NewWriter(os.Stdout, 3, 2, 2, ' ', 0)
for i, a := range sorted {
fmt.Fprintf(tr, "%2d.\t[%v]\t%v", i+1, a.region, a.median())
Expand All @@ -155,59 +155,58 @@ func (w *worker) reportAll() {
tr.Flush()
}

func (w *worker) reportCSV() {
func (w *worker) reportCSV(em map[string]config.Endpoint) {
w.inputs = make(chan input, concurrency)
w.outputs = make(chan output, w.size(region))
w.outputs = make(chan output, w.size(em, region))
for i := 0; i < number; i++ {
for r, e := range config.AllEndpoints {
for r, e := range em {
w.inputs <- input{region: r, endpoint: e.URL}
}
}
close(w.inputs)

sorted := w.sortOutput()
sorted := w.sortOutput(em)
fmt.Println("region,latency_ns,errors")
for _, a := range sorted {
fmt.Printf("%v,%v,%v\n", a.region, a.median().Nanoseconds(), a.errors)
}
}

func (w *worker) reportTop() {
func (w *worker) reportTop(em map[string]config.Endpoint) {
w.inputs = make(chan input, concurrency)
w.outputs = make(chan output, w.size(region))
w.outputs = make(chan output, w.size(em, region))
for i := 0; i < number; i++ {
for r, e := range config.AllEndpoints {
for r, e := range em {
w.inputs <- input{region: r, endpoint: e.URL}
}
}
close(w.inputs)

sorted := w.sortOutput()
sorted := w.sortOutput(em)
t := sorted[0].region
if t == "global" {
t = sorted[1].region
}
fmt.Println(t )
fmt.Println(t)
return
}

func (w *worker) reportRegion(region string) {
func (w *worker) reportRegion(em map[string]config.Endpoint, region string) {
w.inputs = make(chan input, concurrency)
w.outputs = make(chan output, w.size(region))
w.outputs = make(chan output, w.size(em, region))
for i := 0; i < number; i++ {
e, _ := config.AllEndpoints[region]
e, _ := em[region]
w.inputs <- input{region: region, endpoint: e.URL}
}
close(w.inputs)

sorted := w.sortOutput()
sorted := w.sortOutput(em)
fmt.Println(sorted[0].median())

}

func (w *worker) size(region string) int {
func (w *worker) size(em map[string]config.Endpoint, region string) int {
if region != "" {
return number
}
return number * len(config.AllEndpoints)
return number * len(em)
}

0 comments on commit 0f9908c

Please sign in to comment.