Full Code of ekalinin/awsping for AI

master 31ac8c5f70aa cached
19 files
34.2 KB
10.8k tokens
74 symbols
1 requests
Download .txt
Repository: ekalinin/awsping
Branch: master
Commit: 31ac8c5f70aa
Files: 19
Total size: 34.2 KB

Directory structure:
gitextract_d_wjxg93/

├── .dockerignore
├── .github/
│   └── workflows/
│       ├── goreleaser.yml
│       └── pr.yml
├── .gitignore
├── .goreleaser.yml
├── Dockerfile
├── Dockerfile.goreleaser
├── LICENSE
├── Makefile
├── README.md
├── aws.go
├── aws_test.go
├── cmd/
│   └── awsping/
│       └── main.go
├── go.mod
├── request.go
├── request_test.go
├── target.go
├── utils.go
└── utils_test.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
.git
LICENSE
README.md
Dockerfile
awsping


================================================
FILE: .github/workflows/goreleaser.yml
================================================
name: goreleaser

on:
  push:
    branches:
      - "!*"
    tags:
      - "v*.*.*"

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Set up Go
        uses: actions/setup-go@v2
        with:
          go-version: 1.17

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GH_PACKAGE_TOKEN }}

      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v2
        with:
          version: latest
          args: release --rm-dist
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/pr.yml
================================================
name: pr/push checks

on:
  push:
    branches:
      - master
    paths-ignore:
      - '**/*.md'
      - 'Makefile'
  pull_request:
    branches:
      - master
    paths-ignore:
      - '**/*.md'
      - 'Makefile'

jobs:

  build:
    name: Build, Test, Coverage
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: Set up Go
      uses: actions/setup-go@v2
      with:
        go-version: 1.17

    - name: Lint
      uses: golangci/golangci-lint-action@v2

    - name: Build
      run: go build -v ./...

    - name: Test & Coverage
      run: go test -v -coverprofile=coverage.out -covermode=atomic

    - name: Upload coverage to Codecov
      run: bash <(curl -s https://codecov.io/bash)


================================================
FILE: .gitignore
================================================
*.swp
TODO.md
dist/
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
*.prof

coverage.out


================================================
FILE: .goreleaser.yml
================================================
project_name: awsping
builds:
- env:
  - CGO_ENABLED=0
  main: ./cmd/awsping
  goos:
    - linux
    - windows
    - darwin
  goarch:
    - amd64
checksum:
  name_template: 'checksums.txt'
snapshot:
  name_template: "{{ .Tag }}-next"
changelog:
  sort: asc
  filters:
    exclude:
    - '^docs:'
    - '^test:'
    - '^Makefile:'
    - '^README:'
    - '^gitignore:'
    - '^goreleaser:'
dockers:
  - image_templates:
    - "docker.io/evkalinin/{{.ProjectName}}:{{ .Tag }}"
    - "docker.io/evkalinin/{{.ProjectName}}:latest"
    - "ghcr.io/ekalinin/{{.ProjectName}}:{{ .Tag }}"
    - "ghcr.io/ekalinin/{{.ProjectName}}:latest"
    dockerfile: Dockerfile.goreleaser
    build_flag_templates:
    - "--pull"
    - "--label=org.opencontainers.image.created={{.Date}}"
    - "--label=org.opencontainers.image.name={{.ProjectName}}"
    - "--label=org.opencontainers.image.revision={{.FullCommit}}"
    - "--label=org.opencontainers.image.version={{.Version}}"
    - "--label=org.opencontainers.image.source={{.GitURL}}"
    - "--platform=linux/amd64"


================================================
FILE: Dockerfile
================================================
FROM golang:1.17-bullseye as build
COPY . /build
WORKDIR /build
RUN make

FROM gcr.io/distroless/base
COPY --from=build /build/awsping /

ENTRYPOINT ["/awsping"]


================================================
FILE: Dockerfile.goreleaser
================================================
FROM gcr.io/distroless/base
COPY awsping /

ENTRYPOINT ["/awsping"]


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2016 Eugene Kalinin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
NAME=awsping
EXEC=${NAME}
BUILD_DIR=build
BUILD_OS="windows darwin freebsd linux"
BUILD_ARCH="amd64 386"
BUILD_DIR=build
SRC_CMD=cmd/awsping/main.go
VERSION=`grep "Version" utils.go | grep -o -E '[0-9]\.[0-9]\.[0-9]{1,2}'`

build:
	go build -race -o ${EXEC} ${SRC_CMD}

clean:
	@rm -f ${EXEC}
	@rm -f ${BUILD_DIR}/*
	@go clean

#
# Tests, linters
#

lint:
	golint

# make run ARGS="-h"
run:
	go run cmd/awsping/main.go $(ARGS)

test: lint
	@go test -cover .

#
# Release
#
check-version:
ifdef VERSION
	@echo Current version: $(VERSION)
else
	$(error VERSION is not set)
endif

check-master:
ifneq ($(shell git rev-parse --abbrev-ref HEAD),master)
	$(error You're not on the "master" branch)
endif

release: check-master check-version
	git tag v${VERSION} && \
	git push origin v${VERSION}

release-test: check-master check-version
	goreleaser release --snapshot --rm-dist

buildall: clean
	@mkdir -p ${BUILD_DIR}
	@for os in "${BUILD_OS}" ; do \
		for arch in "${BUILD_ARCH}" ; do \
			echo " * build $$os for $$arch"; \
			GOOS=$$os GOARCH=$$arch go build -ldflags "-s" -o ${BUILD_DIR}/${EXEC} ${SRC_CMD}; \
			cd ${BUILD_DIR}; \
			tar czf ${EXEC}.$$os.$$arch.tgz ${EXEC}; \
			cd - ; \
		done done
	@rm ${BUILD_DIR}/${EXEC}

#
# Docker
#

docker:
	docker build -t awsping .

docker-run: docker
	docker run awsping -verbose 2 -repeats 2


================================================
FILE: README.md
================================================
# awsping
Console tool to check the latency to each AWS region

[![Go Report Card](https://goreportcard.com/badge/github.com/ekalinin/awsping)](https://goreportcard.com/report/github.com/ekalinin/awsping)
[![codecov](https://codecov.io/gh/ekalinin/awsping/branch/master/graph/badge.svg)](https://codecov.io/gh/ekalinin/awsping)
[![Go Reference](https://pkg.go.dev/badge/github.com/ekalinin/awsping.svg)](https://pkg.go.dev/github.com/ekalinin/awsping)
[![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/ekalinin/awsping)

# ToC

* [Usage](#usage)
  * [Test via TCP](#test-via-tcp)
  * [Test via HTTP](#test-via-http)
  * [Test via HTTPS](#test-via-https)
  * [Test several times](#test-several-times)
  * [Verbose mode](#verbose-mode)
  * [Get Help](#get-help)
* [Get binary file](#get-binary-file)
* [Build from sources](#build-from-sources)
* [Use with Docker](#use-with-docker)
  * [Build a Docker image](#build-a-docker-image)
  * [Run the Docker image](#run-the-docker-image)

# Usage

## Test via TCP

```bash
➥ ./awsping
Europe (Frankfurt)                    51.86 ms
Europe (Ireland)                      62.86 ms
US-East (Virginia)                   126.39 ms
US-East (Ohio)                       154.81 ms
Asia Pacific (Mumbai)                181.09 ms
US-West (California)                 194.27 ms
US-West (Oregon)                     211.87 ms
South America (São Paulo)            246.20 ms
Asia Pacific (Tokyo)                 309.27 ms
Asia Pacific (Seoul)                 322.76 ms
Asia Pacific (Sydney)                346.37 ms
Asia Pacific (Singapore)             407.91 ms
```

## Test via HTTP

```bash
➥ ./awsping -http
Europe (Frankfurt)                   222.56 ms
Europe (Ireland)                     226.76 ms
US-East (Virginia)                   349.17 ms
US-West (California)                 488.12 ms
US-East (Ohio)                       513.69 ms
Asia Pacific (Mumbai)                528.51 ms
US-West (Oregon)                     532.05 ms
South America (São Paulo)            599.36 ms
Asia Pacific (Seoul)                 715.92 ms
Asia Pacific (Sydney)                721.47 ms
Asia Pacific (Tokyo)                 745.24 ms
Asia Pacific (Singapore)             847.36 ms
```

## Test via HTTPS

```bash
➥ ./awsping -https
Europe (Stockholm)                   216.67 ms
Europe (Frankfurt)                   263.20 ms
Europe (Paris)                       284.32 ms
Europe (Milan)                       305.63 ms
Europe (Ireland)                     327.34 ms
Europe (London)                      332.17 ms
Middle East (Bahrain)                590.74 ms
US-East (N. Virginia)                595.13 ms
Canada (Central)                     628.44 ms
US-East (Ohio)                       635.32 ms
Asia Pacific (Mumbai)                755.56 ms
Asia Pacific (Hong Kong)             843.90 ms
US-West (N. California)              870.65 ms
Asia Pacific (Singapore)             899.50 ms
Africa (Cape Town)                   912.06 ms
US-West (Oregon)                     919.34 ms
South America (São Paulo)            985.93 ms
Asia Pacific (Tokyo)                1122.67 ms
Asia Pacific (Seoul)                1138.76 ms
Asia Pacific (Osaka)                1167.40 ms
Asia Pacific (Sydney)               1328.90 ms
```

## Test several times

```bash
➥ ./awsping -repeats 3
Europe (Frankfurt)                    50.13 ms
Europe (Ireland)                      62.67 ms
US-East (Virginia)                   126.88 ms
US-East (Ohio)                       155.37 ms
US-West (California)                 195.75 ms
US-West (Oregon)                     206.19 ms
Asia Pacific (Mumbai)                222.34 ms
South America (São Paulo)            254.28 ms
Asia Pacific (Tokyo)                 308.52 ms
Asia Pacific (Seoul)                 325.93 ms
Asia Pacific (Sydney)                349.62 ms
Asia Pacific (Singapore)             378.53 ms
```

## Verbose mode

```bash
➥ ./awsping -repeats 3 -verbose 1
      Code            Region                                      Latency
    0 eu-central-1    Europe (Frankfurt)                         47.39 ms
    1 eu-west-1       Europe (Ireland)                           62.28 ms
    2 us-east-1       US-East (Virginia)                        128.45 ms
    3 us-east-2       US-East (Ohio)                            155.53 ms
    4 us-west-1       US-West (California)                      194.37 ms
    5 us-west-2       US-West (Oregon)                          208.91 ms
    6 ap-south-1      Asia Pacific (Mumbai)                     226.59 ms
    7 sa-east-1       South America (São Paulo)                 254.67 ms
    8 ap-northeast-1  Asia Pacific (Tokyo)                      301.97 ms
    9 ap-northeast-2  Asia Pacific (Seoul)                      323.10 ms
   10 ap-southeast-2  Asia Pacific (Sydney)                     341.26 ms
   11 ap-southeast-1  Asia Pacific (Singapore)                  397.47 ms
```

```bash
➥ ./awsping -repeats 3 -verbose 2
      Code            Region                             Try #1          Try #2          Try #3     Avg Latency
    0 eu-central-1    Europe (Frankfurt)               45.18 ms        45.46 ms        45.68 ms        45.44 ms
    1 eu-west-1       Europe (Ireland)                 61.89 ms        62.99 ms        62.98 ms        62.62 ms
    2 us-east-1       US-East (Virginia)              125.15 ms       126.75 ms       126.49 ms       126.13 ms
    3 us-east-2       US-East (Ohio)                  154.05 ms       154.28 ms       153.53 ms       153.96 ms
    4 us-west-1       US-West (California)            196.20 ms       195.05 ms       193.76 ms       195.00 ms
    5 us-west-2       US-West (Oregon)                204.04 ms       203.97 ms       203.84 ms       203.95 ms
    6 ap-south-1      Asia Pacific (Mumbai)           175.27 ms       300.68 ms       172.18 ms       216.05 ms
    7 sa-east-1       South America (São Paulo)       243.48 ms       247.12 ms       248.32 ms       246.31 ms
    8 ap-northeast-1  Asia Pacific (Tokyo)            324.78 ms       312.70 ms       319.02 ms       318.83 ms
    9 ap-northeast-2  Asia Pacific (Seoul)            328.96 ms       327.65 ms       326.17 ms       327.59 ms
   10 ap-southeast-2  Asia Pacific (Sydney)           388.17 ms       347.74 ms       393.58 ms       376.50 ms
   11 ap-southeast-1  Asia Pacific (Singapore)        409.53 ms       403.61 ms       405.84 ms       406.33 ms
```

## Get Help

```bash
➜ ./awsping -h
Usage of ./awsping:
  -http
    	Use http transport (default is tcp)
  -https
    	Use https transport (default is tcp)
  -list-regions
    	Show list of regions
  -repeats int
    	Number of repeats (default 1)
  -service string
    	AWS Service: ec2, sdb, sns, sqs, ... (default "dynamodb")
  -v	Show version
  -verbose int
    	Verbosity level
```

# Get binary file

```bash
$ wget https://github.com/ekalinin/awsping/releases/download/0.5.2/awsping.linux.amd64.tgz
$ tar xzvf awsping.linux.amd64.tgz
$ chmod +x awsping
$ ./awsping -v
0.5.2
```

# Build from sources

```bash
➥ make build
```

# Use with Docker
## Build a Docker image

```
$ docker build -t awsping .
```

## Run the Docker image
```
$ docker run --rm awsping
```

Arguments can be used as mentioned in the _Usage_ section.

i.e.:
```
$ docker run --rm awsping -repeats 3 -verbose 2
```


================================================
FILE: aws.go
================================================
package awsping

import (
	"fmt"
	"sync"
	"time"
)

// CheckType describes a type for a check
type CheckType int

const (
	// CheckTypeTCP is TCP type of check
	CheckTypeTCP CheckType = iota
	// CheckTypeHTTP is HTTP type of check
	CheckTypeHTTP
	// CheckTypeHTTPS is HTTPS type of check
	CheckTypeHTTPS
)

// --------------------------------------------

// AWSRegion description of the AWS EC2 region
type AWSRegion struct {
	Name      string
	Code      string
	Service   string
	Latencies []time.Duration
	Error     error
	CheckType CheckType

	Target  Targetter
	Request Requester
}

// NewRegion creates a new region with a name and code
func NewRegion(name, code string) AWSRegion {
	return AWSRegion{
		Name:      name,
		Code:      code,
		CheckType: CheckTypeTCP,
		Request:   NewAWSRequest(),
	}
}

// CheckLatency does a latency check for a region
func (r *AWSRegion) CheckLatency(wg *sync.WaitGroup) {
	defer wg.Done()

	if r.CheckType == CheckTypeHTTP || r.CheckType == CheckTypeHTTPS {
		r.checkLatencyHTTP(r.CheckType == CheckTypeHTTPS)
	} else {
		r.checkLatencyTCP()
	}
}

// checkLatencyHTTP Test Latency via HTTP
func (r *AWSRegion) checkLatencyHTTP(https bool) {
	url := r.Target.GetURL()
	l, err := r.Request.Do(useragent, url, RequestTypeHTTP)
	if err != nil {
		r.Error = err
		return
	}
	r.Latencies = append(r.Latencies, l)
}

// checkLatencyTCP Test Latency via TCP
func (r *AWSRegion) checkLatencyTCP() {
	tcpAddr, err := r.Target.GetIP()
	if err != nil {
		r.Error = err
		return
	}

	l, err := r.Request.Do(useragent, tcpAddr.String(), RequestTypeTCP)
	if err != nil {
		r.Error = err
		return
	}
	r.Latencies = append(r.Latencies, l)
}

// GetLatency returns Latency in ms
func (r *AWSRegion) GetLatency() float64 {
	sum := float64(0)
	for _, l := range r.Latencies {
		sum += Duration2ms(l)
	}
	return sum / float64(len(r.Latencies))
}

// GetLatencyStr returns Latency in string
func (r *AWSRegion) GetLatencyStr() string {
	if r.Error != nil {
		return r.Error.Error()
	}
	return fmt.Sprintf("%.2f ms", r.GetLatency())
}

// --------------------------------------------

// AWSRegions slice of the AWSRegion
type AWSRegions []AWSRegion

// Len returns a count of regions
func (rs AWSRegions) Len() int {
	return len(rs)
}

// Less return a result of latency compare between two regions
func (rs AWSRegions) Less(i, j int) bool {
	return rs[i].GetLatency() < rs[j].GetLatency()
}

// Swap two regions by index
func (rs AWSRegions) Swap(i, j int) {
	rs[i], rs[j] = rs[j], rs[i]
}

// SetService sets service for all regions
func (rs AWSRegions) SetService(service string) {
	for i := range rs {
		rs[i].Service = service
	}
}

// SetCheckType sets Check Type for all regions
func (rs AWSRegions) SetCheckType(checkType CheckType) {
	for i := range rs {
		rs[i].CheckType = checkType
	}
}

// SetDefaultTarget sets default target instance
func (rs AWSRegions) SetDefaultTarget() {
	rs.SetTarget(func(r *AWSRegion) {
		r.Target = &AWSTarget{
			HTTPS:   r.CheckType == CheckTypeHTTPS,
			Code:    r.Code,
			Service: r.Service,
			Rnd:     mkRandomString(13),
		}
	})
}

// SetTarget sets default target instance for all regions
func (rs AWSRegions) SetTarget(fn func(r *AWSRegion)) {
	for i := range rs {
		fn(&rs[i])
	}
}


================================================
FILE: aws_test.go
================================================
package awsping

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"sync"
	"testing"
	"time"
)

func TestAWSRegionError(t *testing.T) {
	AWSErr := errors.New("something bad")
	r := AWSRegion{Error: AWSErr}

	got := r.GetLatencyStr()
	want := AWSErr.Error()

	if got != want {
		t.Errorf("failed:\ngot=%q\nwant=%q", got, want)
	}
}

type testTarget struct {
	URL string
	IP  *net.TCPAddr
}

func (r *testTarget) GetURL() string {
	return r.URL
}

// GetIP return IP for AWS target
func (r *testTarget) GetIP() (*net.TCPAddr, error) {
	return r.IP, nil
}

func TestAWSRegionCheckLatencyHTTP(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(15 * time.Millisecond)
		fmt.Fprintln(w, "X")
	}))
	defer ts.Close()

	tt := testTarget{URL: ts.URL}

	regions := GetRegions()
	service := "ec2"
	checkType := CheckTypeHTTP

	regions.SetService(service)
	regions.SetCheckType(checkType)
	regions.SetTarget(func(r *AWSRegion) {
		r.Target = &tt
	})

	var wg sync.WaitGroup
	wg.Add(1)
	regions[0].CheckLatency(&wg)

	got := regions[0].GetLatency()
	want := 15.0

	if got < want || got > want*2 {
		t.Errorf("failed:\ngot=%f\nwant=%f", got, want)
	}

	// check "error"
	errTxt := "something bad"
	regions[0].Request = &testRequest{err: errors.New(errTxt)}

	wg.Add(1)
	regions[0].CheckLatency(&wg)

	if regions[0].Error == nil {
		t.Errorf("failed: error should not be empty")
	}

	if regions[0].Error.Error() != errTxt {
		t.Errorf("failed: error should be empty=%s", errTxt)
	}
}

type testRequest struct {
	duration time.Duration
	err      error
}

func (d *testRequest) Do(_, _ string, _ RequestType) (time.Duration, error) {
	if d.err != nil {
		return 0, d.err
	}
	return d.duration, nil
}

func TestAWSRegionCheckLatencyTCP(t *testing.T) {
	// just random local IP
	tt := testTarget{IP: &net.TCPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: 67890,
	}}

	regions := GetRegions()
	service := "ec2"
	checkType := CheckTypeTCP

	regions.SetService(service)
	regions.SetCheckType(checkType)
	regions.SetTarget(func(r *AWSRegion) {
		r.Target = &tt
	})
	regions[0].Request = &testRequest{duration: 15 * time.Millisecond}

	var wg sync.WaitGroup
	wg.Add(1)
	regions[0].CheckLatency(&wg)

	got := regions[0].GetLatency()
	want := 15.0

	if got < want || got > want+1 {
		t.Errorf("failed:\ngot=%f\nwant=%f\nregion=%q", got, want, regions[0])
	}

	if regions[0].Error != nil {
		t.Errorf("failed: error should be empty")
	}

	// check "error"
	errTxt := "something bad"
	regions[0].Request = &testRequest{err: errors.New(errTxt)}

	wg.Add(1)
	regions[0].CheckLatency(&wg)

	if regions[0].Error == nil {
		t.Errorf("failed: error should not be empty")
	}

	if regions[0].Error.Error() != errTxt {
		t.Errorf("failed: error should be empty=%s", errTxt)
	}
}

// ---------------------------------------------

func TestAWSRegionsLen(t *testing.T) {
	regions := GetRegions()

	got := regions.Len()
	want := len(regions)

	if got != want {
		t.Errorf("failed:\ngot=%q\nwant=%q", got, want)
	}
}

func TestAWSRegionsLess(t *testing.T) {
	regions := GetRegions()

	regions[0].Latencies = []time.Duration{15 * time.Millisecond}
	regions[1].Latencies = []time.Duration{25 * time.Millisecond}

	if !regions.Less(0, 1) {
		t.Errorf("failed: not less, regions=%q", regions)
	}
}

func TestAWSRegionsSwap(t *testing.T) {
	regions := GetRegions()

	regions[0].Latencies = []time.Duration{15 * time.Millisecond}
	regions[1].Latencies = []time.Duration{25 * time.Millisecond}

	regions.Swap(0, 3)

	if len(regions[0].Latencies) != 0 {
		t.Errorf("failed: not swapped, regions=%q", regions)
	}
}

func TestAWSRegionsSetService(t *testing.T) {
	regions := GetRegions()
	service := "ec2"

	regions.SetService(service)

	if regions[0].Service != service || regions[len(regions)-1].Service != service {
		t.Errorf("failed: not set, regions=%q, service=%s", regions, service)
	}
}

func TestAWSRegionsSetCheckType(t *testing.T) {
	regions := GetRegions()
	checkType := CheckTypeHTTP

	regions.SetCheckType(checkType)

	if regions[0].CheckType != checkType || regions[len(regions)-1].CheckType != checkType {
		t.Errorf("failed: not set, regions=%q, checkType=%d", regions, checkType)
	}
}

func TestAWSRegionsSetDefaultTarget(t *testing.T) {
	regions := GetRegions()
	service := "ec2"
	checkType := CheckTypeHTTPS

	regions.SetService(service)
	regions.SetCheckType(checkType)
	regions.SetDefaultTarget()

	got := regions[0].Target.GetURL()
	want := fmt.Sprintf("https://ec2.%s.amazonaws.com/ping?x=", regions[0].Code)

	if !strings.HasPrefix(got, want) {
		t.Errorf("failed: wrong url\ngot=%s\nneed=%s", got, want)
	}
}


================================================
FILE: cmd/awsping/main.go
================================================
package main

import (
	"flag"
	"fmt"
	"math/rand"
	"os"
	"time"

	"github.com/ekalinin/awsping"
)

var (
	repeats     = flag.Int("repeats", 1, "Number of repeats")
	useHTTP     = flag.Bool("http", false, "Use http transport (default is tcp)")
	useHTTPS    = flag.Bool("https", false, "Use https transport (default is tcp)")
	showVer     = flag.Bool("v", false, "Show version")
	verbose     = flag.Int("verbose", 0, "Verbosity level (0: name-latency); 1: code-name-latency; 2: code-name-tries-avg")
	service     = flag.String("service", "dynamodb", "AWS Service: ec2, sdb, sns, sqs, ...")
	listRegions = flag.Bool("list-regions", false, "Show list of regions")
)

func main() {
	flag.Parse()

	if *showVer {
		fmt.Println(awsping.Version)
		os.Exit(0)
	}

	regions := awsping.GetRegions()

	if *listRegions {
		lo := awsping.NewOutput(awsping.ShowOnlyRegions, 0)
		lo.Show(&regions)
		os.Exit(0)
	}

	rand.Seed(time.Now().UnixNano())

	awsping.CalcLatency(regions, *repeats, *useHTTP, *useHTTPS, *service)
	lo := awsping.NewOutput(*verbose, *repeats)
	lo.Show(&regions)
}


================================================
FILE: go.mod
================================================
module github.com/ekalinin/awsping

go 1.17


================================================
FILE: request.go
================================================
package awsping

import (
	"net"
	"net/http"
	"time"
)

// RequestType describes a type for a request type
type RequestType int

const (
	// RequestTypeHTTP is HTTP type of request
	RequestTypeHTTP RequestType = iota
	// RequestTypeTCP is TCP type of request
	RequestTypeTCP
)

// Requester is an interface to do a network request
type Requester interface {
	Do(ua, url string, reqType RequestType) (time.Duration, error)
}

// AWSHTTPRequester is an interface for HTTP requests
type AWSHTTPRequester interface {
	Do(req *http.Request) (*http.Response, error)
}

// AWSTCPRequester is an interface for TCP requests
type AWSTCPRequester interface {
	Dial(network, address string) (net.Conn, error)
}

// AWSRequest implements Requester interface
type AWSRequest struct {
	httpClient AWSHTTPRequester
	tcpClient  AWSTCPRequester
}

// NewAWSRequest creates a new instance of AWSRequest
func NewAWSRequest() *AWSRequest {
	return &AWSRequest{
		httpClient: &http.Client{},
		tcpClient:  &net.Dialer{},
	}
}

// DoHTTP does HTTP request for a URL by User-Agent (ua)
func (r *AWSRequest) DoHTTP(ua, url string) (time.Duration, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return 0, err
	}
	req.Header.Set("User-Agent", ua)

	start := time.Now()
	resp, err := r.httpClient.Do(req)
	latency := time.Since(start)

	if err != nil {
		return 0, err
	}
	defer resp.Body.Close()

	return latency, nil
}

// DoTCP does TCP request to the Addr
func (r *AWSRequest) DoTCP(_, addr string) (time.Duration, error) {
	start := time.Now()
	conn, err := r.tcpClient.Dial("tcp", addr)
	if err != nil {
		return 0, err
	}
	l := time.Since(start)
	defer conn.Close()

	return l, nil
}

// Do does a request. Type of request depends on reqType
func (r *AWSRequest) Do(ua, url string, reqType RequestType) (time.Duration, error) {
	if reqType == RequestTypeHTTP {
		return r.DoHTTP(ua, url)
	}
	return r.DoTCP(ua, url)
}


================================================
FILE: request_test.go
================================================
package awsping

import (
	"errors"
	"net"
	"net/http"
	"testing"
)

type testTCPClient struct {
	err error
}

func (c *testTCPClient) Dial(n, a string) (net.Conn, error) {
	if c.err != nil {
		return nil, c.err
	}
	var con net.Conn
	return con, nil
}

type testHTTPClient struct {
	err error
}

func (c *testHTTPClient) Do(r *http.Request) (*http.Response, error) {
	if c.err != nil {
		return nil, c.err
	}
	return &http.Response{}, nil
}

func TestRequestDoTCPError(t *testing.T) {

	r := &AWSRequest{
		tcpClient: &testTCPClient{
			err: net.ErrWriteToConnected,
		},
	}

	l, err := r.DoTCP("net", "some-addr")
	if err == nil {
		t.Errorf("Error should not be empty")
	}
	if !errors.Is(err, net.ErrWriteToConnected) {
		t.Errorf("Want=%v, got=%v", net.ErrWriteToConnected, err)
	}
	if l != 0 {
		t.Errorf("Latency for error should be 0, but got=%d", l)
	}
}

func TestDoErr(t *testing.T) {
	errTCP := errors.New("error from tcp")
	errHTTP := errors.New("error from http")

	r := &AWSRequest{
		tcpClient: &testTCPClient{
			err: errTCP,
		},
		httpClient: &testHTTPClient{
			err: errHTTP,
		},
	}

	l, err := r.Do("ua", "addr", RequestTypeTCP)
	if err == nil {
		t.Errorf("Error should not be empty")
	}
	if !errors.Is(err, errTCP) {
		t.Errorf("Want=%v, got=%v", errTCP, err)
	}
	if l != 0 {
		t.Errorf("Latency for error should be 0, but got=%d", l)
	}

	l, err = r.Do("ua", "addr", RequestTypeHTTP)
	if err == nil {
		t.Errorf("Error should not be empty")
	}
	if !errors.Is(err, errHTTP) {
		t.Errorf("Want=%v, got=%v", errHTTP, err)
	}
	if l != 0 {
		t.Errorf("Latency for error should be 0, but got=%d", l)
	}
}


================================================
FILE: target.go
================================================
package awsping

import (
	"fmt"
	"net"
)

// Targetter is an interface to get target's IP or URL
type Targetter interface {
	GetURL() string
	GetIP() (*net.TCPAddr, error)
}

// AWSTarget implements Targetter for AWS
type AWSTarget struct {
	HTTPS   bool
	Code    string
	Service string
	Rnd     string
}

// GetURL return URL for AWS target
func (r *AWSTarget) GetURL() string {
	proto := "http"
	if r.HTTPS {
		proto = "https"
	}
	hostname := fmt.Sprintf("%s.%s.amazonaws.com", r.Service, r.Code)
	url := fmt.Sprintf("%s://%s/ping?x=%s", proto, hostname, r.Rnd)
	return url
}

// GetIP return IP for AWS target
func (r *AWSTarget) GetIP() (*net.TCPAddr, error) {
	tcpURI := fmt.Sprintf("%s.%s.amazonaws.com:80", r.Service, r.Code)
	return net.ResolveTCPAddr("tcp4", tcpURI)
}


================================================
FILE: utils.go
================================================
package awsping

import (
	"fmt"
	"io"
	"math/rand"
	"os"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	// Version describes application version
	Version   = "2.0.0"
	github    = "https://github.com/ekalinin/awsping"
	useragent = fmt.Sprintf("AwsPing/%s (+%s)", Version, github)
)

const (
	// ShowOnlyRegions describes a type of output when only region's name and code printed out
	ShowOnlyRegions = -1
)

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

// Duration2ms converts time.Duration to ms (float64)
func Duration2ms(d time.Duration) float64 {
	return float64(d.Nanoseconds()) / 1000 / 1000
}

// mkRandomString returns random string
func mkRandomString(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

// LatencyOutput prints data into console
type LatencyOutput struct {
	Level   int
	Repeats int
	w       io.Writer
}

// NewOutput creates a new LatencyOutput instance
func NewOutput(level, repeats int) *LatencyOutput {
	return &LatencyOutput{
		Level:   level,
		Repeats: repeats,
		w:       os.Stdout,
	}
}

func (lo *LatencyOutput) show(regions *AWSRegions) {
	for _, r := range *regions {
		fmt.Fprintf(lo.w, "%-15s %-s\n", r.Code, r.Name)
	}
}

func (lo *LatencyOutput) show0(regions *AWSRegions) {
	for _, r := range *regions {
		fmt.Fprintf(lo.w, "%-25s %20s\n", r.Name, r.GetLatencyStr())
	}
}

func (lo *LatencyOutput) show1(regions *AWSRegions) {
	outFmt := "%5v %-15s %-30s %20s\n"
	fmt.Fprintf(lo.w, outFmt, "", "Code", "Region", "Latency")
	for i, r := range *regions {
		fmt.Fprintf(lo.w, outFmt, i, r.Code, r.Name, r.GetLatencyStr())
	}
}

func (lo *LatencyOutput) show2(regions *AWSRegions) {
	// format
	outFmt := "%5v %-15s %-25s"
	outFmt += strings.Repeat(" %15s", lo.Repeats) + " %15s\n"
	// header
	outStr := []interface{}{"", "Code", "Region"}
	for i := 0; i < lo.Repeats; i++ {
		outStr = append(outStr, "Try #"+strconv.Itoa(i+1))
	}
	outStr = append(outStr, "Avg Latency")

	// show header
	fmt.Fprintf(lo.w, outFmt, outStr...)

	// each region stats
	for i, r := range *regions {
		outData := []interface{}{strconv.Itoa(i), r.Code, r.Name}
		for n := 0; n < lo.Repeats; n++ {
			outData = append(outData, fmt.Sprintf("%.2f ms",
				Duration2ms(r.Latencies[n])))
		}
		outData = append(outData, fmt.Sprintf("%.2f ms", r.GetLatency()))
		fmt.Fprintf(lo.w, outFmt, outData...)
	}
}

// Show print data
func (lo *LatencyOutput) Show(regions *AWSRegions) {
	switch lo.Level {
	case ShowOnlyRegions:
		lo.show(regions)
	case 0:
		lo.show0(regions)
	case 1:
		lo.show1(regions)
	case 2:
		lo.show2(regions)
	}
}

// GetRegions returns a list of regions
func GetRegions() AWSRegions {
	return AWSRegions{
		NewRegion("Africa (Cape Town)", "af-south-1"),
		NewRegion("Asia Pacific (Hong Kong)", "ap-east-1"),
		NewRegion("Asia Pacific (Tokyo)", "ap-northeast-1"),
		NewRegion("Asia Pacific (Seoul)", "ap-northeast-2"),
		NewRegion("Asia Pacific (Osaka)", "ap-northeast-3"),
		NewRegion("Asia Pacific (Mumbai)", "ap-south-1"),
		NewRegion("Asia Pacific (Hyderabad)", "ap-south-2"),
		NewRegion("Asia Pacific (Singapore)", "ap-southeast-1"),
		NewRegion("Asia Pacific (Sydney)", "ap-southeast-2"),
		NewRegion("Asia Pacific (Jakarta)", "ap-southeast-3"),
		NewRegion("Asia Pacific (Melbourne)", "ap-southeast-4"),
		NewRegion("Canada (Central)", "ca-central-1"),
		NewRegion("Europe (Frankfurt)", "eu-central-1"),
		NewRegion("Europe (Zurich)", "eu-central-2"),
		NewRegion("Europe (Stockholm)", "eu-north-1"),
		NewRegion("Europe (Milan)", "eu-south-1"),
		NewRegion("Europe (Spain)", "eu-south-2"),
		NewRegion("Europe (Ireland)", "eu-west-1"),
		NewRegion("Europe (London)", "eu-west-2"),
		NewRegion("Europe (Paris)", "eu-west-3"),
		NewRegion("Middle East (UAE)", "me-central-1"),
		NewRegion("Middle East (Bahrain)", "me-south-1"),
		NewRegion("South America (Sao Paulo)", "sa-east-1"),
		NewRegion("US East (N. Virginia)", "us-east-1"),
		NewRegion("US East (Ohio)", "us-east-2"),
		NewRegion("US West (N. California)", "us-west-1"),
		NewRegion("US West (Oregon)", "us-west-2"),
		NewRegion("Israel (Tel Aviv)", "il-central-1"),
	}
}

// CalcLatency returns list of aws regions sorted by Latency
func CalcLatency(regions AWSRegions, repeats int, useHTTP bool, useHTTPS bool, service string) {
	regions.SetService(service)
	switch {
	case useHTTP:
		regions.SetCheckType(CheckTypeHTTP)
	case useHTTPS:
		regions.SetCheckType(CheckTypeHTTPS)
	default:
		regions.SetCheckType(CheckTypeTCP)
	}
	regions.SetDefaultTarget()

	var wg sync.WaitGroup
	for n := 1; n <= repeats; n++ {
		wg.Add(len(regions))
		for i := range regions {
			go regions[i].CheckLatency(&wg)
		}
		wg.Wait()
	}

	sort.Sort(regions)
}


================================================
FILE: utils_test.go
================================================
package awsping

import (
	"bytes"
	"testing"
	"time"
)

func TestDuration(t *testing.T) {
	input := time.Duration(1 * time.Second)
	want := 1000.0
	got := Duration2ms(input)
	if got != want {
		t.Errorf("Duration was incorrect, got: %f, want: %f.", got, want)
	}
}

func TestRandomString(t *testing.T) {
	tests := []struct {
		n   int
		res string
	}{
		{1, ""},
		{5, ""},
		{10, ""},
	}

	for idx, test := range tests {
		test.res = mkRandomString(test.n)
		if len(test.res) != test.n {
			t.Errorf("Try %d: n=%d, got: %s (len=%d), want: %d.",
				idx, test.n, test.res, len(test.res), test.n)
		}
	}
}

func TestOutputShowOnlyRegions(t *testing.T) {
	var b bytes.Buffer

	lo := NewOutput(ShowOnlyRegions, 0)
	lo.w = &b

	regions := GetRegions()[:2]
	lo.Show(&regions)

	got := b.String()
	want := "af-south-1      Africa (Cape Town)\n" +
		"ap-east-1       Asia Pacific (Hong Kong)\n"

	if got != want {
		t.Errorf("Show:\ngot =%q\nwant=%q", got, want)
	}
}

func TestOutputShow0(t *testing.T) {
	var b bytes.Buffer

	lo := NewOutput(0, 0)
	lo.w = &b

	regions := GetRegions()[:2]
	regions[0].Latencies = []time.Duration{15 * time.Millisecond}
	regions[1].Latencies = []time.Duration{25 * time.Millisecond}

	lo.Show(&regions)

	want := "Africa (Cape Town)                    15.00 ms\n" +
		"Asia Pacific (Hong Kong)              25.00 ms\n"
	got := b.String()
	if got != want {
		t.Errorf("Show0 failed:\ngot =%q\nwant=%q", got, want)
	}
}

func TestOutputShow1(t *testing.T) {
	var b bytes.Buffer

	lo := NewOutput(1, 0)
	lo.w = &b

	regions := GetRegions()[:2]
	regions[0].Latencies = []time.Duration{15 * time.Millisecond}
	regions[1].Latencies = []time.Duration{25 * time.Millisecond}

	lo.Show(&regions)

	got := b.String()
	want := "      Code            Region                                      Latency\n" +
		"    0 af-south-1      Africa (Cape Town)                         15.00 ms\n" +
		"    1 ap-east-1       Asia Pacific (Hong Kong)                   25.00 ms\n"
	if got != want {
		t.Errorf("Show1 failed:\ngot =%q\nwant=%q", got, want)
	}
}

func TestOutputShow2(t *testing.T) {
	var b bytes.Buffer

	lo := NewOutput(2, 2)
	lo.w = &b

	regions := GetRegions()[:2]
	regions[0].Latencies = []time.Duration{15 * time.Millisecond, 17 * time.Millisecond}
	regions[1].Latencies = []time.Duration{25 * time.Millisecond, 26 * time.Millisecond}

	lo.Show(&regions)

	got := b.String()
	want := "      Code            Region                             Try #1          Try #2     Avg Latency\n" +
		"    0 af-south-1      Africa (Cape Town)               15.00 ms        17.00 ms        16.00 ms\n" +
		"    1 ap-east-1       Asia Pacific (Hong Kong)         25.00 ms        26.00 ms        25.50 ms\n"
	if got != want {
		t.Errorf("Show2 failed:\ngot =%q\nwant=%q", got, want)
	}
}

func TestCalcLatency(t *testing.T) {

	regions := GetRegions()[:3]
	regions[0].Request = &testRequest{duration: 30 * time.Millisecond}
	regions[1].Request = &testRequest{duration: 7 * time.Millisecond}
	regions[2].Request = &testRequest{duration: 15 * time.Millisecond}

	regionsStats := make(AWSRegions, regions.Len())

	checkSort := func(origIndex, sortedIdx int) {
		got := regionsStats[sortedIdx].Name
		want := regions[origIndex].Name

		if got != want {
			t.Errorf("CalcLatency failed:\ngot=%q\nwant=%q\norig=%d\nsorted=%d",
				got, want, origIndex, sortedIdx)
		}
	}

	for i := 1; i < 4; i++ {
		copy(regionsStats, regions)

		switch i {
		case 1:
			CalcLatency(regionsStats, 1, false, false, "ec2")
		case 2:
			CalcLatency(regionsStats, 1, true, false, "ec2")
		default:
			CalcLatency(regionsStats, 1, true, true, "ec2")
		}

		checkSort(0, 2)
		checkSort(1, 0)
		checkSort(2, 1)
	}
}
Download .txt
gitextract_d_wjxg93/

├── .dockerignore
├── .github/
│   └── workflows/
│       ├── goreleaser.yml
│       └── pr.yml
├── .gitignore
├── .goreleaser.yml
├── Dockerfile
├── Dockerfile.goreleaser
├── LICENSE
├── Makefile
├── README.md
├── aws.go
├── aws_test.go
├── cmd/
│   └── awsping/
│       └── main.go
├── go.mod
├── request.go
├── request_test.go
├── target.go
├── utils.go
└── utils_test.go
Download .txt
SYMBOL INDEX (74 symbols across 8 files)

FILE: aws.go
  type CheckType (line 10) | type CheckType
  constant CheckTypeTCP (line 14) | CheckTypeTCP CheckType = iota
  constant CheckTypeHTTP (line 16) | CheckTypeHTTP
  constant CheckTypeHTTPS (line 18) | CheckTypeHTTPS
  type AWSRegion (line 24) | type AWSRegion struct
    method CheckLatency (line 47) | func (r *AWSRegion) CheckLatency(wg *sync.WaitGroup) {
    method checkLatencyHTTP (line 58) | func (r *AWSRegion) checkLatencyHTTP(https bool) {
    method checkLatencyTCP (line 69) | func (r *AWSRegion) checkLatencyTCP() {
    method GetLatency (line 85) | func (r *AWSRegion) GetLatency() float64 {
    method GetLatencyStr (line 94) | func (r *AWSRegion) GetLatencyStr() string {
  function NewRegion (line 37) | func NewRegion(name, code string) AWSRegion {
  type AWSRegions (line 104) | type AWSRegions
    method Len (line 107) | func (rs AWSRegions) Len() int {
    method Less (line 112) | func (rs AWSRegions) Less(i, j int) bool {
    method Swap (line 117) | func (rs AWSRegions) Swap(i, j int) {
    method SetService (line 122) | func (rs AWSRegions) SetService(service string) {
    method SetCheckType (line 129) | func (rs AWSRegions) SetCheckType(checkType CheckType) {
    method SetDefaultTarget (line 136) | func (rs AWSRegions) SetDefaultTarget() {
    method SetTarget (line 148) | func (rs AWSRegions) SetTarget(fn func(r *AWSRegion)) {

FILE: aws_test.go
  function TestAWSRegionError (line 15) | func TestAWSRegionError(t *testing.T) {
  type testTarget (line 27) | type testTarget struct
    method GetURL (line 32) | func (r *testTarget) GetURL() string {
    method GetIP (line 37) | func (r *testTarget) GetIP() (*net.TCPAddr, error) {
  function TestAWSRegionCheckLatencyHTTP (line 41) | func TestAWSRegionCheckLatencyHTTP(t *testing.T) {
  type testRequest (line 87) | type testRequest struct
    method Do (line 92) | func (d *testRequest) Do(_, _ string, _ RequestType) (time.Duration, e...
  function TestAWSRegionCheckLatencyTCP (line 99) | func TestAWSRegionCheckLatencyTCP(t *testing.T) {
  function TestAWSRegionsLen (line 150) | func TestAWSRegionsLen(t *testing.T) {
  function TestAWSRegionsLess (line 161) | func TestAWSRegionsLess(t *testing.T) {
  function TestAWSRegionsSwap (line 172) | func TestAWSRegionsSwap(t *testing.T) {
  function TestAWSRegionsSetService (line 185) | func TestAWSRegionsSetService(t *testing.T) {
  function TestAWSRegionsSetCheckType (line 196) | func TestAWSRegionsSetCheckType(t *testing.T) {
  function TestAWSRegionsSetDefaultTarget (line 207) | func TestAWSRegionsSetDefaultTarget(t *testing.T) {

FILE: cmd/awsping/main.go
  function main (line 23) | func main() {

FILE: request.go
  type RequestType (line 10) | type RequestType
  constant RequestTypeHTTP (line 14) | RequestTypeHTTP RequestType = iota
  constant RequestTypeTCP (line 16) | RequestTypeTCP
  type Requester (line 20) | type Requester interface
  type AWSHTTPRequester (line 25) | type AWSHTTPRequester interface
  type AWSTCPRequester (line 30) | type AWSTCPRequester interface
  type AWSRequest (line 35) | type AWSRequest struct
    method DoHTTP (line 49) | func (r *AWSRequest) DoHTTP(ua, url string) (time.Duration, error) {
    method DoTCP (line 69) | func (r *AWSRequest) DoTCP(_, addr string) (time.Duration, error) {
    method Do (line 82) | func (r *AWSRequest) Do(ua, url string, reqType RequestType) (time.Dur...
  function NewAWSRequest (line 41) | func NewAWSRequest() *AWSRequest {

FILE: request_test.go
  type testTCPClient (line 10) | type testTCPClient struct
    method Dial (line 14) | func (c *testTCPClient) Dial(n, a string) (net.Conn, error) {
  type testHTTPClient (line 22) | type testHTTPClient struct
    method Do (line 26) | func (c *testHTTPClient) Do(r *http.Request) (*http.Response, error) {
  function TestRequestDoTCPError (line 33) | func TestRequestDoTCPError(t *testing.T) {
  function TestDoErr (line 53) | func TestDoErr(t *testing.T) {

FILE: target.go
  type Targetter (line 9) | type Targetter interface
  type AWSTarget (line 15) | type AWSTarget struct
    method GetURL (line 23) | func (r *AWSTarget) GetURL() string {
    method GetIP (line 34) | func (r *AWSTarget) GetIP() (*net.TCPAddr, error) {

FILE: utils.go
  constant ShowOnlyRegions (line 24) | ShowOnlyRegions = -1
  function Duration2ms (line 30) | func Duration2ms(d time.Duration) float64 {
  function mkRandomString (line 35) | func mkRandomString(n int) string {
  type LatencyOutput (line 44) | type LatencyOutput struct
    method show (line 59) | func (lo *LatencyOutput) show(regions *AWSRegions) {
    method show0 (line 65) | func (lo *LatencyOutput) show0(regions *AWSRegions) {
    method show1 (line 71) | func (lo *LatencyOutput) show1(regions *AWSRegions) {
    method show2 (line 79) | func (lo *LatencyOutput) show2(regions *AWSRegions) {
    method Show (line 106) | func (lo *LatencyOutput) Show(regions *AWSRegions) {
  function NewOutput (line 51) | func NewOutput(level, repeats int) *LatencyOutput {
  function GetRegions (line 120) | func GetRegions() AWSRegions {
  function CalcLatency (line 154) | func CalcLatency(regions AWSRegions, repeats int, useHTTP bool, useHTTPS...

FILE: utils_test.go
  function TestDuration (line 9) | func TestDuration(t *testing.T) {
  function TestRandomString (line 18) | func TestRandomString(t *testing.T) {
  function TestOutputShowOnlyRegions (line 37) | func TestOutputShowOnlyRegions(t *testing.T) {
  function TestOutputShow0 (line 55) | func TestOutputShow0(t *testing.T) {
  function TestOutputShow1 (line 75) | func TestOutputShow1(t *testing.T) {
  function TestOutputShow2 (line 96) | func TestOutputShow2(t *testing.T) {
  function TestCalcLatency (line 117) | func TestCalcLatency(t *testing.T) {
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (39K chars).
[
  {
    "path": ".dockerignore",
    "chars": 42,
    "preview": ".git\nLICENSE\nREADME.md\nDockerfile\nawsping\n"
  },
  {
    "path": ".github/workflows/goreleaser.yml",
    "chars": 971,
    "preview": "name: goreleaser\n\non:\n  push:\n    branches:\n      - \"!*\"\n    tags:\n      - \"v*.*.*\"\n\njobs:\n  goreleaser:\n    runs-on: ub"
  },
  {
    "path": ".github/workflows/pr.yml",
    "chars": 727,
    "preview": "name: pr/push checks\n\non:\n  push:\n    branches:\n      - master\n    paths-ignore:\n      - '**/*.md'\n      - 'Makefile'\n  "
  },
  {
    "path": ".gitignore",
    "chars": 300,
    "preview": "*.swp\nTODO.md\ndist/\n# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test"
  },
  {
    "path": ".goreleaser.yml",
    "chars": 1048,
    "preview": "project_name: awsping\nbuilds:\n- env:\n  - CGO_ENABLED=0\n  main: ./cmd/awsping\n  goos:\n    - linux\n    - windows\n    - dar"
  },
  {
    "path": "Dockerfile",
    "chars": 162,
    "preview": "FROM golang:1.17-bullseye as build\nCOPY . /build\nWORKDIR /build\nRUN make\n\nFROM gcr.io/distroless/base\nCOPY --from=build "
  },
  {
    "path": "Dockerfile.goreleaser",
    "chars": 68,
    "preview": "FROM gcr.io/distroless/base\nCOPY awsping /\n\nENTRYPOINT [\"/awsping\"]\n"
  },
  {
    "path": "LICENSE",
    "chars": 1071,
    "preview": "MIT License\n\nCopyright (c) 2016 Eugene Kalinin\n\nPermission is hereby granted, free of charge, to any person obtaining a "
  },
  {
    "path": "Makefile",
    "chars": 1340,
    "preview": "NAME=awsping\nEXEC=${NAME}\nBUILD_DIR=build\nBUILD_OS=\"windows darwin freebsd linux\"\nBUILD_ARCH=\"amd64 386\"\nBUILD_DIR=build"
  },
  {
    "path": "README.md",
    "chars": 7431,
    "preview": "# awsping\nConsole tool to check the latency to each AWS region\n\n[![Go Report Card](https://goreportcard.com/badge/github"
  },
  {
    "path": "aws.go",
    "chars": 3253,
    "preview": "package awsping\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n)\n\n// CheckType describes a type for a check\ntype CheckType int\n\nconst "
  },
  {
    "path": "aws_test.go",
    "chars": 4679,
    "preview": "package awsping\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\""
  },
  {
    "path": "cmd/awsping/main.go",
    "chars": 1072,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/ekalinin/awsping\"\n)\n\nvar (\n\trepeats     ="
  },
  {
    "path": "go.mod",
    "chars": 44,
    "preview": "module github.com/ekalinin/awsping\n\ngo 1.17\n"
  },
  {
    "path": "request.go",
    "chars": 1924,
    "preview": "package awsping\n\nimport (\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n)\n\n// RequestType describes a type for a request type\ntype RequestT"
  },
  {
    "path": "request_test.go",
    "chars": 1622,
    "preview": "package awsping\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"net/http\"\n\t\"testing\"\n)\n\ntype testTCPClient struct {\n\terr error\n}\n\nfunc (c *"
  },
  {
    "path": "target.go",
    "chars": 779,
    "preview": "package awsping\n\nimport (\n\t\"fmt\"\n\t\"net\"\n)\n\n// Targetter is an interface to get target's IP or URL\ntype Targetter interfa"
  },
  {
    "path": "utils.go",
    "chars": 4763,
    "preview": "package awsping\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"os\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar (\n\t// Ver"
  },
  {
    "path": "utils_test.go",
    "chars": 3697,
    "preview": "package awsping\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestDuration(t *testing.T) {\n\tinput := time.Duration(1 * t"
  }
]

About this extraction

This page contains the full source code of the ekalinin/awsping GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (34.2 KB), approximately 10.8k tokens, and a symbol index with 74 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!