mirror of
https://github.com/Luzifer/mondash.git
synced 2024-11-09 16:10:01 +00:00
Major: Rework frontend, API and improve code quality (#5)
* Update dependencies * Improve code quality * Apply linter advices * Add gzip compression to all requests * Rework frontend * Apply bootswatch theme * Hide historic details when not requested * Remove debugging header * Apply auto-migration of meta fields * Fix broken "last update" time * Pre-sort metrics for frontend / API * Add tooltip with absolute time * Some design fixes * Add tooltip with absolute date to last ok * Implement filters * Apply eslint --fix * Remove unused var * Remove remains of old template engine * Update baked in assets * Update Dockerfile for new version Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
27fc5093c0
commit
f3c31476b4
3576 changed files with 263838 additions and 2169770 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,5 +1,8 @@
|
|||
cmd/mondash-nagios/mondash-nagios
|
||||
data
|
||||
.env
|
||||
frontend/app.js
|
||||
gin-bin
|
||||
mondash
|
||||
*.sh
|
||||
data
|
||||
cmd/mondash-nagios/mondash-nagios
|
||||
src/node_modules
|
||||
|
|
22
Dockerfile
22
Dockerfile
|
@ -1,24 +1,38 @@
|
|||
FROM node:alpine as node_builder
|
||||
|
||||
COPY . /src/mondash
|
||||
WORKDIR /src/mondash/src
|
||||
|
||||
RUN set -ex \
|
||||
&& npm ci \
|
||||
&& npm run build
|
||||
|
||||
|
||||
FROM golang:alpine as builder
|
||||
|
||||
ADD . /go/src/github.com/Luzifer/mondash
|
||||
COPY . /go/src/github.com/Luzifer/mondash
|
||||
WORKDIR /go/src/github.com/Luzifer/mondash
|
||||
|
||||
RUN set -ex \
|
||||
&& apk add --update git \
|
||||
&& go install -ldflags "-X main.version=$(git describe --tags || git rev-parse --short HEAD || echo dev)"
|
||||
&& go install -ldflags "-X main.version=$(git describe --tags --always || echo dev)"
|
||||
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
ENV FRONTEND_DIR=/usr/local/share/mondash/frontend \
|
||||
STORAGE=file:///data
|
||||
|
||||
LABEL maintainer "Knut Ahlers <knut@ahlers.me>"
|
||||
|
||||
RUN set -ex \
|
||||
&& apk --no-cache add ca-certificates
|
||||
|
||||
COPY --from=builder /go/bin/mondash /usr/local/bin/mondash
|
||||
COPY --from=builder /go/src/github.com/Luzifer/mondash/templates /usr/local/share/mondash/templates
|
||||
COPY --from=node_builder /src/mondash/frontend /usr/local/share/mondash/frontend
|
||||
|
||||
WORKDIR /usr/local/share/mondash
|
||||
EXPOSE 3000
|
||||
VOLUME ["/data"]
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/mondash"]
|
||||
CMD ["--"]
|
||||
|
|
190
Gopkg.lock
generated
190
Gopkg.lock
generated
|
@ -2,109 +2,171 @@
|
|||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:70792ca3a262117f2135feb54379a0399fc8afb267edc64a16ee278dd431a619"
|
||||
name = "github.com/Luzifer/go_helpers"
|
||||
packages = [
|
||||
"accessLogger",
|
||||
"http",
|
||||
"str",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "77c32c00ab0b3717afcee0a42567d603dccdf158"
|
||||
version = "v2.9.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f6cc072a289a686fda22819d871cd1b0407640141b2f6616dfbab957c96bf6c3"
|
||||
name = "github.com/Luzifer/rconfig"
|
||||
packages = ["."]
|
||||
revision = "7aef1d393c1e2d0758901853b59981c7adc67c7e"
|
||||
version = "v1.2.0"
|
||||
pruneopts = "NUT"
|
||||
revision = "d38bbb45e0ac240398f2af710a6b21833954f006"
|
||||
version = "v2.2.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b5ecadb8c242ff0f9191e201af8152e38a763637ea777d35a761d1420eecdc11"
|
||||
name = "github.com/aws/aws-sdk-go"
|
||||
packages = ["aws","aws/awserr","aws/awsutil","aws/client","aws/client/metadata","aws/corehandlers","aws/credentials","aws/credentials/ec2rolecreds","aws/credentials/endpointcreds","aws/credentials/stscreds","aws/defaults","aws/ec2metadata","aws/endpoints","aws/request","aws/session","aws/signer/v4","internal/shareddefaults","private/protocol","private/protocol/query","private/protocol/query/queryutil","private/protocol/rest","private/protocol/restxml","private/protocol/xml/xmlutil","service/s3","service/sts"]
|
||||
revision = "991fe2497a95d757bb53f95cbcebf3d26134c9fe"
|
||||
version = "v1.12.32"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/extemporalgenome/slug"
|
||||
packages = ["."]
|
||||
revision = "0320c85e32e0015b090f08a5d1324d5ab6094f07"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/flosch/go-humanize"
|
||||
packages = ["."]
|
||||
revision = "3ba51eabe50663842d569003bab93fc256883173"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/flosch/pongo2"
|
||||
packages = ["."]
|
||||
revision = "5e81b817a0c48c1c57cdf1a9056cf76bdee02ca9"
|
||||
version = "v3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/flosch/pongo2-addons"
|
||||
packages = ["."]
|
||||
revision = "86b9b7b8051253fbb41b3fff8a8f5cc9c300305e"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-ini/ini"
|
||||
packages = ["."]
|
||||
revision = "32e4c1e6bc4e7d0d8451aa6b75200d19e37a536a"
|
||||
version = "v1.32.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/context"
|
||||
packages = ["."]
|
||||
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
|
||||
version = "v1.1"
|
||||
packages = [
|
||||
"aws",
|
||||
"aws/awserr",
|
||||
"aws/awsutil",
|
||||
"aws/client",
|
||||
"aws/client/metadata",
|
||||
"aws/corehandlers",
|
||||
"aws/credentials",
|
||||
"aws/credentials/ec2rolecreds",
|
||||
"aws/credentials/endpointcreds",
|
||||
"aws/credentials/processcreds",
|
||||
"aws/credentials/stscreds",
|
||||
"aws/csm",
|
||||
"aws/defaults",
|
||||
"aws/ec2metadata",
|
||||
"aws/endpoints",
|
||||
"aws/request",
|
||||
"aws/session",
|
||||
"aws/signer/v4",
|
||||
"internal/ini",
|
||||
"internal/s3err",
|
||||
"internal/sdkio",
|
||||
"internal/sdkrand",
|
||||
"internal/sdkuri",
|
||||
"internal/shareddefaults",
|
||||
"private/protocol",
|
||||
"private/protocol/eventstream",
|
||||
"private/protocol/eventstream/eventstreamapi",
|
||||
"private/protocol/json/jsonutil",
|
||||
"private/protocol/query",
|
||||
"private/protocol/query/queryutil",
|
||||
"private/protocol/rest",
|
||||
"private/protocol/restxml",
|
||||
"private/protocol/xml/xmlutil",
|
||||
"service/s3",
|
||||
"service/sts",
|
||||
]
|
||||
pruneopts = "NUT"
|
||||
revision = "a4072efa95b76eb4d8eaebe701abee730cce3e60"
|
||||
version = "v1.19.37"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:caf94762c0e0a1bdd44d9307d319f2841939399c86db9f04b4d2e470c51aa007"
|
||||
name = "github.com/gorilla/mux"
|
||||
packages = ["."]
|
||||
revision = "7f08801859139f86dfafd1c296e2cba9a80d292e"
|
||||
version = "v1.6.0"
|
||||
pruneopts = "NUT"
|
||||
revision = "ed099d42384823742bba0bf9a72b53b55c9e2e38"
|
||||
version = "v1.7.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:974a3957354622ffb7b0b345374322f782800a8e4c4517022fce77ef796249c5"
|
||||
name = "github.com/gosimple/slug"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "e78d39397ba41d2c33d9615044ef93eca8a309d8"
|
||||
version = "v1.5.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1f2aebae7e7c856562355ec0198d8ca2fa222fb05e5b1b66632a1fce39631885"
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
packages = ["."]
|
||||
revision = "0b12d6b5"
|
||||
pruneopts = "NUT"
|
||||
revision = "c2b33e84"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:58999a98719fddbac6303cb17e8d85b945f60b72f48e3a2df6b950b97fa926f1"
|
||||
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "f55edac94c9bbba5d6182a4be46d86a2c9b5b50e"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:14715f705ff5dfe0ffd6571d7d201dd8e921030f8070321a79380d8ca4ec1a24"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
pruneopts = "NUT"
|
||||
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
|
||||
version = "v0.8.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/juju/errors"
|
||||
digest = "1:16e2136a67ec44aa2d1d6b0fd65394b3c4a8b2a1b6730c77967f7b7b06b179b2"
|
||||
name = "github.com/rainycape/unidecode"
|
||||
packages = ["."]
|
||||
revision = "c7d06af17c68cd34c835053720b21f6549d9b0ee"
|
||||
pruneopts = "NUT"
|
||||
revision = "cb7f23ec59bec0d61b19c56cd88cee3d0cc1870c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/russross/blackfriday"
|
||||
digest = "1:f4aaa07a6c33f2b354726d0571acbc8ca118837c75709f6353203ae1a3f8eeab"
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
revision = "cadec560ec52d93835bf2f15bd794700d3a2473b"
|
||||
version = "v2.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/shurcooL/sanitized_anchor_name"
|
||||
packages = ["."]
|
||||
revision = "86672fcb3f950f35f2e675df2240550f2a50762f"
|
||||
pruneopts = "NUT"
|
||||
revision = "839c75faf7f98a33d445d181f3018b5c3409a45e"
|
||||
version = "v1.4.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9d8420bbf131d1618bde6530af37c3799340d3762cc47210c1d9532a4c3a2779"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
||||
version = "v1.0.0"
|
||||
pruneopts = "NUT"
|
||||
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/text"
|
||||
packages = ["internal/gen","internal/triegen","internal/ucd","transform","unicode/cldr","unicode/norm"]
|
||||
revision = "88f656faf3f37f690df1a32515b479415e1a6769"
|
||||
digest = "1:19269bc82d61ac4ddeb697c45b21ae4b014370a2254c116a2e61582cbe74ce2d"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
pruneopts = "NUT"
|
||||
revision = "0e01d883c5c5e3a1741118a9962f68d71b0a6ed4"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
digest = "1:1ab6db2d2bd353449c5d1e976ba7a92a0ece6e83aaab3e6674f8f2f1faebb85a"
|
||||
name = "gopkg.in/validator.v2"
|
||||
packages = ["."]
|
||||
revision = "460c83432a98c35224a6fe352acf8b23e067ad06"
|
||||
pruneopts = "NUT"
|
||||
revision = "135c24b11c19e52befcae2ec3fca5d9b78c4e98e"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
digest = "1:18108594151654e9e696b27b181b953f9a90b16bf14d253dd1b397b025a1487f"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "287cf08546ab5e7e37d55a84f7ed3fd1db036de5"
|
||||
pruneopts = "NUT"
|
||||
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
|
||||
version = "v2.2.2"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "d6eacc94cd9bd400bffbca99280d82e6e82fad1f84460edb4d4fc0fc78df83f1"
|
||||
input-imports = [
|
||||
"github.com/Luzifer/go_helpers/http",
|
||||
"github.com/Luzifer/go_helpers/str",
|
||||
"github.com/Luzifer/rconfig",
|
||||
"github.com/aws/aws-sdk-go/aws",
|
||||
"github.com/aws/aws-sdk-go/aws/awserr",
|
||||
"github.com/aws/aws-sdk-go/aws/session",
|
||||
"github.com/aws/aws-sdk-go/service/s3",
|
||||
"github.com/gorilla/mux",
|
||||
"github.com/gosimple/slug",
|
||||
"github.com/pkg/errors",
|
||||
"github.com/sirupsen/logrus",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
47
Gopkg.toml
47
Gopkg.toml
|
@ -1,7 +1,6 @@
|
|||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
|
@ -17,26 +16,44 @@
|
|||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/Luzifer/go_helpers"
|
||||
version = "2.9.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/Luzifer/rconfig"
|
||||
version = "1.2.0"
|
||||
version = "2.2.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/aws/aws-sdk-go"
|
||||
version = "1.12.32"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/flosch/pongo2"
|
||||
version = "3.0.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/flosch/pongo2-addons"
|
||||
version = "1.19.37"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gorilla/mux"
|
||||
version = "1.6.0"
|
||||
version = "1.7.2"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gosimple/slug"
|
||||
version = "1.5.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/pkg/errors"
|
||||
version = "0.8.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/sirupsen/logrus"
|
||||
version = "1.4.2"
|
||||
|
||||
[prune]
|
||||
non-go = true
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
|
14
Makefile
14
Makefile
|
@ -1,3 +1,17 @@
|
|||
default:
|
||||
|
||||
frontend:
|
||||
docker run --rm -i \
|
||||
-v "$(CURDIR):$(CURDIR)" \
|
||||
-w "$(CURDIR)/src" \
|
||||
node:alpine \
|
||||
sh -c "npm ci && npm run build && chown -R $(shell id -u):$(shell id -g) ../frontend node_modules"
|
||||
|
||||
pack: frontend
|
||||
go-bindata -o assets.go frontend/...
|
||||
|
||||
publish:
|
||||
curl -sSLo golang.sh https://raw.githubusercontent.com/Luzifer/github-publish/master/golang.sh
|
||||
bash golang.sh
|
||||
|
||||
.PHONY: frontend
|
||||
|
|
|
@ -18,9 +18,9 @@ type Status string
|
|||
// Collection of available status strings
|
||||
const (
|
||||
StatusOK Status = "OK"
|
||||
StatusWarning = "Warning"
|
||||
StatusCritical = "Critical"
|
||||
StatusUnknown = "Unknown"
|
||||
StatusWarning Status = "Warning"
|
||||
StatusCritical Status = "Critical"
|
||||
StatusUnknown Status = "Unknown"
|
||||
)
|
||||
|
||||
// Client represents an accessor to the MonDash API
|
||||
|
@ -46,7 +46,7 @@ func (c *Client) do(method, path string, body io.Reader) error {
|
|||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", c.token)
|
||||
req.Header.Set("Authorization", "Token "+c.token)
|
||||
|
||||
req = req.WithContext(c.context)
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
|
@ -83,7 +83,7 @@ func (c *Client) WithContext(ctx context.Context) *Client {
|
|||
|
||||
// DeleteDashboard will delete all your monitoring results available on your dashboard and release the dashboard URL to the public
|
||||
func (c *Client) DeleteDashboard() error {
|
||||
return c.do("DELETE", "/"+c.board, nil)
|
||||
return c.do(http.MethodDelete, "/"+c.board, nil)
|
||||
}
|
||||
|
||||
// PostMetricInput contains parameters for the API request
|
||||
|
@ -155,7 +155,7 @@ func (c *Client) PostMetric(input *PostMetricInput) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return c.do("PUT", "/"+c.board+"/"+input.MetricID, buf)
|
||||
return c.do(http.MethodPut, "/"+c.board+"/"+input.MetricID, buf)
|
||||
}
|
||||
|
||||
// DeleteMetricInput contains parameters for the API request
|
||||
|
@ -166,5 +166,5 @@ type DeleteMetricInput struct {
|
|||
|
||||
// DeleteMetric deletes a metric from your dashboard
|
||||
func (c *Client) DeleteMetric(input *DeleteMetricInput) error {
|
||||
return c.do("DELETE", "/"+c.board+"/"+input.MetricID, nil)
|
||||
return c.do(http.MethodDelete, "/"+c.board+"/"+input.MetricID, nil)
|
||||
}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
package config // import "github.com/Luzifer/mondash/config"
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/url"
|
||||
|
||||
"github.com/Luzifer/rconfig"
|
||||
)
|
||||
|
||||
var storageDrivers = []string{"s3", "file"}
|
||||
|
||||
// Config is a storage struct for configuration parameters
|
||||
type Config struct {
|
||||
Storage string `flag:"storage" default:"s3" description:"Storage engine to use"`
|
||||
BaseURL string `flag:"baseurl" env:"BASE_URL" description:"The Base-URL the application is running on for example https://mondash.org"`
|
||||
APIToken string `flag:"api-token" env:"API_TOKEN" description:"API Token used for the /welcome dashboard (you can choose your own)"`
|
||||
|
||||
Listen string `flag:"listen" default:":3000" description:"Address to listen on"`
|
||||
|
||||
S3 struct {
|
||||
Bucket string `flag:"s3Bucket" env:"S3Bucket" "Bucket to use for S3 storage"`
|
||||
}
|
||||
|
||||
FileStorage struct {
|
||||
Directory string `flag:"fileDirectory" default:"./" description:"Directory to use for plain text storage"`
|
||||
}
|
||||
}
|
||||
|
||||
// Load parses arguments / ENV variable to load configuration
|
||||
func Load() *Config {
|
||||
cfg := &Config{}
|
||||
rconfig.Parse(cfg)
|
||||
return cfg
|
||||
}
|
||||
|
||||
func (c Config) isValid() bool {
|
||||
// Storage Driver check
|
||||
validStoragedriver := false
|
||||
for _, d := range storageDrivers {
|
||||
if c.Storage == d {
|
||||
validStoragedriver = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !validStoragedriver {
|
||||
log.Printf("You specified a wrong storage driver: %s\n\n", c.Storage)
|
||||
return false
|
||||
}
|
||||
|
||||
// Minimum characters of API token
|
||||
if len(c.APIToken) < 10 {
|
||||
log.Printf("You need to specify an api-token with more than 9 characters.\n\n")
|
||||
return false
|
||||
}
|
||||
|
||||
// Base-URL check
|
||||
if _, err := url.Parse(c.BaseURL); err != nil {
|
||||
log.Printf("The baseurl '%s' does not look like a valid URL: %s.\n\n", c.BaseURL, err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package filters
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
humanize "github.com/flosch/go-humanize"
|
||||
"github.com/flosch/pongo2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
pongo2.RegisterFilter("lastNItems", filterLastNItems)
|
||||
pongo2.RegisterFilter("naturaltime", filterTimeuntilTimesince)
|
||||
}
|
||||
|
||||
func filterLastNItems(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
|
||||
if !in.CanSlice() {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
from := in.Len() - param.Integer()
|
||||
if from < 0 {
|
||||
from = 0
|
||||
}
|
||||
|
||||
return in.Slice(from, in.Len()), nil
|
||||
}
|
||||
|
||||
func filterTimeuntilTimesince(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
|
||||
basetime, isTime := in.Interface().(time.Time)
|
||||
if !isTime {
|
||||
return nil, &pongo2.Error{
|
||||
Sender: "filter:timeuntil/timesince",
|
||||
ErrorMsg: "time-value is not a time.Time-instance",
|
||||
}
|
||||
}
|
||||
var paramtime time.Time
|
||||
if !param.IsNil() {
|
||||
paramtime, isTime = param.Interface().(time.Time)
|
||||
if !isTime {
|
||||
return nil, &pongo2.Error{
|
||||
Sender: "filter:timeuntil/timesince",
|
||||
ErrorMsg: "time-parameter is not a time.Time-instance",
|
||||
}
|
||||
}
|
||||
} else {
|
||||
paramtime = time.Now()
|
||||
}
|
||||
|
||||
return pongo2.AsValue(humanize.TimeDuration(basetime.Sub(paramtime))), nil
|
||||
}
|
18
frontend/index.html
Normal file
18
frontend/index.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css"
|
||||
integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay" crossorigin="anonymous">
|
||||
|
||||
<title>MonDash - Dashboard</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,40 +0,0 @@
|
|||
package main
|
||||
|
||||
import "net/http"
|
||||
|
||||
// LogResponseWriter wraps the standard http.ResponseWritter allowing for more
|
||||
// verbose logging
|
||||
type LogResponseWriter struct {
|
||||
Status int
|
||||
Size int
|
||||
http.ResponseWriter
|
||||
}
|
||||
|
||||
// NewLogResponseWriter instanciates a new LogResponseWriter
|
||||
func NewLogResponseWriter(res http.ResponseWriter) *LogResponseWriter {
|
||||
// Default the status code to 200
|
||||
return &LogResponseWriter{200, 0, res}
|
||||
}
|
||||
|
||||
// Header returns & satisfies the http.ResponseWriter interface
|
||||
func (w *LogResponseWriter) Header() http.Header {
|
||||
return w.ResponseWriter.Header()
|
||||
}
|
||||
|
||||
// Write satisfies the http.ResponseWriter interface and
|
||||
// captures data written, in bytes
|
||||
func (w *LogResponseWriter) Write(data []byte) (int, error) {
|
||||
|
||||
written, err := w.ResponseWriter.Write(data)
|
||||
w.Size += written
|
||||
|
||||
return written, err
|
||||
}
|
||||
|
||||
// WriteHeader satisfies the http.ResponseWriter interface and
|
||||
// allows us to cach the status code
|
||||
func (w *LogResponseWriter) WriteHeader(statusCode int) {
|
||||
|
||||
w.Status = statusCode
|
||||
w.ResponseWriter.WriteHeader(statusCode)
|
||||
}
|
116
main.go
116
main.go
|
@ -3,72 +3,97 @@ package main
|
|||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Luzifer/mondash/config"
|
||||
"github.com/Luzifer/mondash/storage"
|
||||
"github.com/flosch/pongo2"
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
_ "github.com/Luzifer/mondash/filters"
|
||||
httphelper "github.com/Luzifer/go_helpers/http"
|
||||
"github.com/Luzifer/mondash/storage"
|
||||
"github.com/Luzifer/rconfig"
|
||||
)
|
||||
|
||||
var (
|
||||
templates = make(map[string]*pongo2.Template)
|
||||
store storage.Storage
|
||||
cfg *config.Config
|
||||
store storage.Storage
|
||||
cfg = struct {
|
||||
APIToken string `flag:"api-token" env:"API_TOKEN" description:"API Token used for the /welcome dashboard (you can choose your own)"`
|
||||
BaseURL string `flag:"baseurl" env:"BASE_URL" description:"The Base-URL the application is running on for example https://mondash.org"`
|
||||
FrontendDir string `flag:"frontend-dir" default:"./frontend" description:"Directory to serve frontend assets from"`
|
||||
Storage string `flag:"storage" default:"file:///./data" description:"Storage engine to use"`
|
||||
|
||||
version string
|
||||
Listen string `flag:"listen" default:":3000" description:"Address to listen on"`
|
||||
LogLevel string `flag:"log-level" default:"info" description:"Set log level (debug, info, warning, error)"`
|
||||
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
|
||||
}{}
|
||||
|
||||
version = "dev"
|
||||
)
|
||||
|
||||
func main() {
|
||||
preloadTemplates()
|
||||
func init() {
|
||||
rconfig.AutoEnv(true)
|
||||
if err := rconfig.ParseAndValidate(&cfg); err != nil {
|
||||
log.Fatalf("Unable to parse commandline options: %s", err)
|
||||
}
|
||||
|
||||
if l, err := log.ParseLevel(cfg.LogLevel); err == nil {
|
||||
log.SetLevel(l)
|
||||
} else {
|
||||
log.Fatalf("Invalid log level: %s", err)
|
||||
}
|
||||
|
||||
if cfg.VersionAndExit {
|
||||
fmt.Printf("share %s\n", version)
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
cfg = config.Load()
|
||||
store, err = storage.GetStorage(cfg)
|
||||
if err != nil {
|
||||
fmt.Printf("An error occurred while loading the storage handler: %s", err)
|
||||
|
||||
if store, err = storage.GetStorage(cfg.Storage); err != nil {
|
||||
log.WithError(err).Fatal("Unable to load storage handler")
|
||||
}
|
||||
|
||||
r := mux.NewRouter()
|
||||
r.Use( // Sort: Outermost to innermost wrapper
|
||||
httphelper.NewHTTPLogHandler,
|
||||
httphelper.GzipHandler,
|
||||
genericHeader,
|
||||
)
|
||||
|
||||
r.HandleFunc("/", handleRedirectWelcome).
|
||||
Methods("GET")
|
||||
Methods(http.MethodGet)
|
||||
r.HandleFunc("/app.js", handleAppJS).
|
||||
Methods(http.MethodGet)
|
||||
|
||||
r.HandleFunc("/create", handleCreateRandomDashboard).
|
||||
Methods("GET")
|
||||
Methods(http.MethodGet)
|
||||
r.HandleFunc("/{dashid}.json", handleDisplayDashboardJSON).
|
||||
Methods("GET")
|
||||
Methods(http.MethodGet)
|
||||
r.HandleFunc("/{dashid}", handleDisplayDashboard).
|
||||
Methods("GET")
|
||||
Methods(http.MethodGet)
|
||||
|
||||
r.HandleFunc("/{dashid}/{metricid}", handlePutMetric).
|
||||
Methods("PUT")
|
||||
Methods(http.MethodPut)
|
||||
|
||||
r.HandleFunc("/{dashid}", handleDeleteDashboard).
|
||||
Methods("DELETE")
|
||||
Methods(http.MethodDelete)
|
||||
r.HandleFunc("/{dashid}/{metricid}", handleDeleteMetric).
|
||||
Methods("DELETE")
|
||||
Methods(http.MethodDelete)
|
||||
|
||||
go runWelcomePage(cfg)
|
||||
go runWelcomePage()
|
||||
|
||||
http.Handle("/", logHTTPRequest(r))
|
||||
http.ListenAndServe(cfg.Listen, nil)
|
||||
if err := http.ListenAndServe(cfg.Listen, r); err != nil {
|
||||
log.WithError(err).Fatal("HTTP server ended unexpectedly")
|
||||
}
|
||||
}
|
||||
|
||||
func logHTTPRequest(h http.Handler) http.Handler {
|
||||
func genericHeader(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now().UnixNano()
|
||||
w := NewLogResponseWriter(res)
|
||||
|
||||
w.Header().Set("X-Application-Version", version)
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
|
||||
d := (time.Now().UnixNano() - start) / 1000
|
||||
log.Printf("%s %s %d %dµs %dB\n", r.Method, r.URL.Path, w.Status, d, w.Size)
|
||||
res.Header().Set("X-Application-Version", version)
|
||||
h.ServeHTTP(res, r)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -77,22 +102,3 @@ func generateAPIKey() string {
|
|||
sum := md5.Sum([]byte(t))
|
||||
return fmt.Sprintf("%x", sum)
|
||||
}
|
||||
|
||||
func renderTemplate(templateName string, context pongo2.Context, res http.ResponseWriter) {
|
||||
if tpl, ok := templates[templateName]; ok {
|
||||
_ = tpl.ExecuteWriter(context, res)
|
||||
} else {
|
||||
res.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = res.Write([]byte(fmt.Sprintf("Template %s not found!", templateName)))
|
||||
}
|
||||
}
|
||||
|
||||
func preloadTemplates() {
|
||||
templateNames, err := ioutil.ReadDir("templates")
|
||||
if err != nil {
|
||||
panic("Templates directory not available!")
|
||||
}
|
||||
for _, tplname := range templateNames {
|
||||
templates[tplname.Name()] = pongo2.Must(pongo2.FromFile(fmt.Sprintf("templates/%s", tplname.Name())))
|
||||
}
|
||||
}
|
||||
|
|
33
math.go
Normal file
33
math.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func absoluteDeviation(values []float64) []float64 {
|
||||
medianValue := median(values)
|
||||
|
||||
deviation := make([]float64, len(values))
|
||||
|
||||
for i := range values {
|
||||
deviation[i] = math.Abs(values[i] - medianValue)
|
||||
}
|
||||
|
||||
return deviation
|
||||
}
|
||||
|
||||
func median(values []float64) float64 {
|
||||
sort.Float64s(values)
|
||||
|
||||
if len(values) == 1 {
|
||||
return values[0]
|
||||
}
|
||||
|
||||
// If even, take an average
|
||||
if len(values)%2 == 0 {
|
||||
return 0.5*values[len(values)/2] + 0.5*values[len(values)/2-1]
|
||||
}
|
||||
|
||||
return values[len(values)/2-1]
|
||||
}
|
89
src/.eslintrc.js
Normal file
89
src/.eslintrc.js
Normal file
|
@ -0,0 +1,89 @@
|
|||
// https://eslint.org/docs/user-guide/configuring
|
||||
|
||||
module.exports = {
|
||||
'root': true,
|
||||
'parserOptions': {
|
||||
parser: 'babel-eslint',
|
||||
sourceType: 'module',
|
||||
},
|
||||
'env': {
|
||||
node: true,
|
||||
},
|
||||
'extends': [
|
||||
/*
|
||||
* https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
|
||||
* consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
|
||||
*/
|
||||
'plugin:vue/essential',
|
||||
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
|
||||
'eslint:recommended',
|
||||
],
|
||||
// required to lint *.vue files
|
||||
'plugins': ['vue'],
|
||||
'globals': {
|
||||
locale: true,
|
||||
process: true,
|
||||
version: true,
|
||||
},
|
||||
// add your custom rules here
|
||||
'rules': {
|
||||
'array-bracket-newline': ['error', { multiline: true }],
|
||||
'array-bracket-spacing': ['error'],
|
||||
'arrow-body-style': ['error', 'as-needed'],
|
||||
'arrow-parens': ['error', 'as-needed'],
|
||||
'arrow-spacing': ['error', { before: true, after: true }],
|
||||
'block-spacing': ['error'],
|
||||
'brace-style': ['error', '1tbs'],
|
||||
'comma-dangle': ['error', 'always-multiline'], // Apply Contentflow rules
|
||||
'comma-spacing': ['error'],
|
||||
'comma-style': ['error', 'last'],
|
||||
'curly': ['error'],
|
||||
'dot-location': ['error', 'property'],
|
||||
'dot-notation': ['error'],
|
||||
'eol-last': ['error', 'always'],
|
||||
'eqeqeq': ['error', 'always', { 'null': 'ignore' }],
|
||||
'func-call-spacing': ['error', 'never'],
|
||||
'function-paren-newline': ['error', 'multiline'],
|
||||
'generator-star-spacing': ['off'], // allow async-await
|
||||
'implicit-arrow-linebreak': ['error'],
|
||||
'indent': ['error', 2],
|
||||
'key-spacing': ['error', { beforeColon: false, afterColon: true, mode: 'strict' }],
|
||||
'keyword-spacing': ['error'],
|
||||
'linebreak-style': ['error', 'unix'],
|
||||
'lines-between-class-members': ['error'],
|
||||
'multiline-comment-style': ['warn'],
|
||||
'newline-per-chained-call': ['error'],
|
||||
'no-console': ['off'],
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', // allow debugger during development
|
||||
'no-else-return': ['error'],
|
||||
'no-extra-parens': ['error'],
|
||||
'no-implicit-coercion': ['error'],
|
||||
'no-lonely-if': ['error'],
|
||||
'no-multiple-empty-lines': ['warn', { max: 2, maxEOF: 0, maxBOF: 0 }],
|
||||
'no-multi-spaces': ['error'],
|
||||
'no-trailing-spaces': ['error'],
|
||||
'no-unneeded-ternary': ['error'],
|
||||
'no-useless-return': ['error'],
|
||||
'no-whitespace-before-property': ['error'],
|
||||
'object-curly-newline': ['error', { consistent: true }],
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
'object-shorthand': ['error'],
|
||||
'padded-blocks': ['error', 'never'],
|
||||
'prefer-arrow-callback': ['error'],
|
||||
'prefer-const': ['error'],
|
||||
'prefer-object-spread': ['error'],
|
||||
'prefer-template': ['error'],
|
||||
'quote-props': ['error', 'consistent-as-needed', { keywords: true }],
|
||||
'quotes': ['error', 'single', { allowTemplateLiterals: true }],
|
||||
'semi': ['error', 'never'],
|
||||
'space-before-blocks': ['error', 'always'],
|
||||
'spaced-comment': ['warn', 'always'],
|
||||
'space-infix-ops': ['error'],
|
||||
'space-in-parens': ['error', 'never'],
|
||||
'space-unary-ops': ['error', { words: true, nonwords: false }],
|
||||
'switch-colon-spacing': ['error'],
|
||||
'unicode-bom': ['error', 'never'],
|
||||
'wrap-iife': ['error'],
|
||||
'yoda': ['error'],
|
||||
},
|
||||
}
|
157
src/app.vue
Normal file
157
src/app.vue
Normal file
|
@ -0,0 +1,157 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<b-navbar toggleable="lg" type="light" variant="light">
|
||||
<b-navbar-brand href="welcome">MonDash</b-navbar-brand>
|
||||
|
||||
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
|
||||
|
||||
<b-collapse id="nav-collapse" is-nav>
|
||||
<b-navbar-nav>
|
||||
<b-nav-item href="http://docs.mondash.apiary.io/" target="_blank">API Docs</b-nav-item>
|
||||
</b-navbar-nav>
|
||||
|
||||
<!-- Right aligned nav items -->
|
||||
<b-navbar-nav class="ml-auto">
|
||||
<b-nav-item @click="show_filters = !show_filters">Toggle Filters</b-nav-item>
|
||||
<b-nav-item href="/create">Get your own dashboard</b-nav-item>
|
||||
</b-navbar-nav>
|
||||
</b-collapse>
|
||||
</b-navbar>
|
||||
|
||||
<b-container class="mt-4">
|
||||
|
||||
<b-row v-if="dash_id == 'welcome'">
|
||||
<b-col>
|
||||
<b-jumbotron header="Welcome to MonDash!" class="text-center">
|
||||
<p>You're currently seeing a demo dashboard updated with random numbers below. To get started read the <a href="http://docs.mondash.apiary.io/" target="_blank">API documentation</a> and create your own dashboard by clicking the button in the upper right hand corner…
|
||||
<p>If you have any questions about this project don't hesitate to ask <a href="https://ahlers.me/" target="_blank">Knut</a>.</p>
|
||||
</b-jumbotron>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-row v-else-if="api_key && !metrics" class="justify-content-md-center">
|
||||
<b-col cols="12" md="6" class="text-center">
|
||||
<p>Welcome to your new dashboard. Your API-key is:</p>
|
||||
|
||||
<code>{{ api_key }}</code>
|
||||
|
||||
<p>
|
||||
After you sent your first metric you can reach your dashboard here:<br>
|
||||
<a :href="location">{{ location }}</a>
|
||||
</p>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-row v-if="show_filters" class="mb-4">
|
||||
<b-col>
|
||||
<b-card bg-variant="primary" text-variant="white">
|
||||
<b-row>
|
||||
<b-col cols="8">
|
||||
<b-form-group label="Filter by text:">
|
||||
<b-form-input v-model="filter_text" placeholder="Filter metrics by title / description"></b-form-input>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
<b-col cols="4">
|
||||
<b-form-group label="Filter by status:">
|
||||
<b-form-select v-model="level_filter" :options="level_filters"></b-form-select>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-card>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<metric v-for="metric in filtered_metrics" :metric="metric" :key="metric.id"></metric>
|
||||
|
||||
</b-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
import metric from './metric.vue'
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
|
||||
components: {
|
||||
metric,
|
||||
},
|
||||
computed: {
|
||||
dash_id() {
|
||||
return window.location.pathname.substr(1)
|
||||
},
|
||||
|
||||
filtered_metrics() {
|
||||
const filter_text = this.filter_text.toLowerCase()
|
||||
|
||||
if (filter_text === '' && this.level_filter === 3) {
|
||||
// No-filter: Don't waste resources
|
||||
return this.metrics
|
||||
}
|
||||
|
||||
const levels = ['OK', 'Warning', 'Critical', 'Unknown']
|
||||
const metrics = []
|
||||
|
||||
for (const metric of this.metrics) {
|
||||
// Filter by level
|
||||
if (levels.indexOf(metric.status) < this.level_filter && this.level_filter !== 3) {
|
||||
// Level is lower than selected and selected is not "ALL"
|
||||
continue
|
||||
}
|
||||
|
||||
// Filter by text
|
||||
if (filter_text !== '' && metric.title.toLowerCase().indexOf(filter_text) < 0 && metric.description.toLowerCase().indexOf(filter_text) < 0) {
|
||||
// Neither title nor description contained filter but filter was set
|
||||
continue
|
||||
}
|
||||
|
||||
metrics.push(metric)
|
||||
}
|
||||
|
||||
return metrics
|
||||
},
|
||||
|
||||
location() {
|
||||
return window.location.href
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
api_key: null,
|
||||
filter_text: '',
|
||||
level_filter: 3,
|
||||
level_filters: [
|
||||
{ value: 3, text: 'Unknown, OK, Warning, Critical' },
|
||||
{ value: 0, text: 'OK, Warning, Critical' },
|
||||
{ value: 1, text: 'Warning, Critical' },
|
||||
{ value: 2, text: 'Critical' },
|
||||
],
|
||||
metrics: [],
|
||||
show_filters: false,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateDashboardData() {
|
||||
const path = window.location.pathname
|
||||
axios.get(`${path}.json?history_bar=true&value_history=true`)
|
||||
.then(resp => {
|
||||
this.api_key = resp.data.api_key
|
||||
this.metrics = resp.data.metrics
|
||||
})
|
||||
.catch(err => console.error(err))
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.updateDashboardData()
|
||||
window.setInterval(() => this.updateDashboardData(), 10000)
|
||||
},
|
||||
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
51
src/graph.vue
Normal file
51
src/graph.vue
Normal file
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div class="ct-double-octave" ref="container"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import chartist from 'chartist'
|
||||
import moment from 'moment'
|
||||
|
||||
export default {
|
||||
name: 'graph',
|
||||
props: ['metric'],
|
||||
|
||||
computed: {
|
||||
data() {
|
||||
const vh = this.metric.value_history
|
||||
|
||||
const labels = []
|
||||
const series = []
|
||||
|
||||
for (const k of Object.keys(vh)) {
|
||||
labels.push(moment(k * 1000).format('lll'))
|
||||
series.push(vh[k])
|
||||
}
|
||||
|
||||
return {
|
||||
labels,
|
||||
series: [series],
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.chart = chartist.Line(this.$refs.container, this.data)
|
||||
},
|
||||
|
||||
watch: {
|
||||
metric() {
|
||||
this.chart.update(this.data)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
35
src/history-bar.vue
Normal file
35
src/history-bar.vue
Normal file
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<b-progress class="w-100" :max="10000">
|
||||
<b-progress-bar
|
||||
:key="seg.start"
|
||||
:value="seg.percentage * 10000"
|
||||
:variant="variantFromStatus(seg.status)"
|
||||
:title="`${moment(seg.start).format('lll')}\n${moment(seg.end).format('lll')}`"
|
||||
v-b-tooltip.hover
|
||||
v-for="seg in metric.history_bar"
|
||||
>
|
||||
</b-progress-bar>
|
||||
</b-progress>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment'
|
||||
|
||||
export default {
|
||||
name: 'history-bar',
|
||||
props: ['metric'],
|
||||
|
||||
methods: {
|
||||
moment,
|
||||
|
||||
variantFromStatus(status) {
|
||||
return {
|
||||
OK: 'success',
|
||||
Warning: 'warning',
|
||||
Critical: 'danger',
|
||||
Unknown: 'info',
|
||||
}[status]
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
17
src/main.js
Normal file
17
src/main.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import Vue from 'vue'
|
||||
import BootstrapVue from 'bootstrap-vue'
|
||||
|
||||
import app from './app.vue'
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.css'
|
||||
import 'bootstrap-vue/dist/bootstrap-vue.css'
|
||||
import 'bootswatch/dist/cosmo/bootstrap.min.css'
|
||||
import 'chartist/dist/chartist.min.css'
|
||||
|
||||
Vue.use(BootstrapVue)
|
||||
|
||||
new Vue({
|
||||
components: { app },
|
||||
el: '#app',
|
||||
render: c => c('app'),
|
||||
})
|
64
src/metric.vue
Normal file
64
src/metric.vue
Normal file
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<b-row class="mb-3">
|
||||
<b-col>
|
||||
<b-card :border-variant="variantFromStatus(metric.status)">
|
||||
|
||||
<b-row slot="header">
|
||||
<b-col cols="7">
|
||||
<strong>{{ metric.title }}</strong>
|
||||
</b-col>
|
||||
<b-col class="d-flex align-items-center" cols="5">
|
||||
<historyBar :metric="metric"></historyBar>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-card-text>
|
||||
{{ metric.description }}
|
||||
</b-card-text>
|
||||
|
||||
<graph :metric="metric" v-if="!metric.config.hide_mad"></graph>
|
||||
|
||||
<div slot="footer" class="d-flex justify-content-between">
|
||||
<span>
|
||||
<b-badge :variant="variantFromStatus(metric.status)" v-if="!metric.config.hide_value">Current value: {{ metric.value.toFixed(3) }}</b-badge>
|
||||
<span v-if="!metric.config.hide_mad">
|
||||
<abbr title="Median Absolute Deviation">MAD</abbr>: {{ metric.mad_multiplier.toFixed(3) }} above the median ({{ metric.median.toFixed(3) }})
|
||||
</span>
|
||||
</span>
|
||||
<small class="text-muted">
|
||||
<span v-b-tooltip.hover :title="moment(metric.last_update).format('lll')">Updated {{ moment(metric.last_update).fromNow() }}</span>
|
||||
<span v-b-tooltip.hover :title="moment(metric.last_ok).format('lll')" v-if="metric.status !== 'OK'"> (Last OK {{ moment(metric.last_ok).fromNow() }})</span>
|
||||
</small>
|
||||
</div>
|
||||
|
||||
</b-card>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment'
|
||||
|
||||
import graph from './graph.vue'
|
||||
import historyBar from './history-bar.vue'
|
||||
|
||||
export default {
|
||||
name: 'metric',
|
||||
props: ['metric'],
|
||||
|
||||
components: { graph, historyBar },
|
||||
|
||||
methods: {
|
||||
moment,
|
||||
|
||||
variantFromStatus(status) {
|
||||
return {
|
||||
OK: 'success',
|
||||
Warning: 'warning',
|
||||
Critical: 'danger',
|
||||
Unknown: 'info',
|
||||
}[status]
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
6862
src/package-lock.json
generated
Normal file
6862
src/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
35
src/package.json
Normal file
35
src/package.json
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"author": "",
|
||||
"description": "",
|
||||
"devDependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"bootstrap": "^4.3.1",
|
||||
"bootstrap-vue": "^2.0.0-rc.20",
|
||||
"bootswatch": "^4.3.1",
|
||||
"css-loader": "^1.0.0",
|
||||
"moment": "^2.24.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"sass-loader": "^7.0.3",
|
||||
"style-loader": "^0.21.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-loader": "^15.7.0",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"webpack": "^4.16.2",
|
||||
"webpack-cli": "^3.1.0",
|
||||
"webpack-dev-middleware": "^1.4.0",
|
||||
"webpack-hot-middleware": "^2.9.1"
|
||||
},
|
||||
"license": "ISC",
|
||||
"name": "mondash",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "webpack -p"
|
||||
},
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"chartist": "^0.11.0"
|
||||
}
|
||||
}
|
54
src/webpack.config.js
Normal file
54
src/webpack.config.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||
|
||||
module.exports = {
|
||||
entry: './main.js',
|
||||
output: {
|
||||
filename: 'app.js',
|
||||
path: path.resolve(__dirname, '..', 'frontend'),
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.OccurrenceOrderPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: JSON.stringify('production'),
|
||||
},
|
||||
}),
|
||||
new VueLoaderPlugin(),
|
||||
],
|
||||
optimization: {
|
||||
minimize: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
|
||||
{
|
||||
test: /\.(s?)css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
'css-loader',
|
||||
'sass-loader',
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /(node_modules|bower_components)/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [['env', { targets: { browsers: ['>0.25%', 'not ie 11', 'not op_mini all'] } }]],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
},
|
||||
|
||||
],
|
||||
},
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
package storage // import "github.com/Luzifer/mondash/storage"
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/Luzifer/mondash/config"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Storage is an interface to have all storage systems compatible to each other
|
||||
|
@ -14,16 +15,6 @@ type Storage interface {
|
|||
Exists(dashboardID string) (bool, error)
|
||||
}
|
||||
|
||||
// AdapterNotFoundError is a named error for more simple determination which
|
||||
// type of error is thrown
|
||||
type AdapterNotFoundError struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (e AdapterNotFoundError) Error() string {
|
||||
return fmt.Sprintf("Storage '%s' not found.", e.Name)
|
||||
}
|
||||
|
||||
// DashboardNotFoundError signalizes the requested dashboard could not be found
|
||||
type DashboardNotFoundError struct {
|
||||
DashboardID string
|
||||
|
@ -35,13 +26,18 @@ func (e DashboardNotFoundError) Error() string {
|
|||
|
||||
// GetStorage acts as a storage factory providing the storage named by input
|
||||
// name parameter
|
||||
func GetStorage(cfg *config.Config) (Storage, error) {
|
||||
switch cfg.Storage {
|
||||
case "s3":
|
||||
return NewS3Storage(cfg), nil
|
||||
case "file":
|
||||
return NewFileStorage(cfg), nil
|
||||
func GetStorage(uri string) (Storage, error) {
|
||||
u, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Invalid storage URI")
|
||||
}
|
||||
|
||||
return nil, AdapterNotFoundError{cfg.Storage}
|
||||
switch u.Scheme {
|
||||
case "s3":
|
||||
return NewS3Storage(u), nil
|
||||
case "file":
|
||||
return NewFileStorage(u), nil
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("Storage %q not found", u.Scheme)
|
||||
}
|
||||
|
|
|
@ -1,31 +1,30 @@
|
|||
package storage // import "github.com/Luzifer/mondash/storage"
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/Luzifer/mondash/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// FileStorage is a storage adapter storing the data into single local files
|
||||
type FileStorage struct {
|
||||
cfg *config.Config
|
||||
storagePath string
|
||||
}
|
||||
|
||||
// NewFileStorage instanciates a new FileStorage
|
||||
func NewFileStorage(cfg *config.Config) *FileStorage {
|
||||
func NewFileStorage(uri *url.URL) *FileStorage {
|
||||
// Create directory if not exists
|
||||
if _, err := os.Stat(cfg.FileStorage.Directory); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(cfg.FileStorage.Directory, 0700); err != nil {
|
||||
fmt.Printf("Could not create storage directory '%s'", cfg.FileStorage.Directory)
|
||||
os.Exit(1)
|
||||
if _, err := os.Stat(uri.Path); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(uri.Path, 0700); err != nil {
|
||||
log.WithError(err).Fatal("Could not create storage directory")
|
||||
}
|
||||
}
|
||||
|
||||
return &FileStorage{
|
||||
cfg: cfg,
|
||||
storagePath: uri.Path,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,5 +69,5 @@ func (f *FileStorage) Exists(dashboardID string) (bool, error) {
|
|||
}
|
||||
|
||||
func (f *FileStorage) getFilePath(dashboardID string) string {
|
||||
return path.Join(f.cfg.FileStorage.Directory, dashboardID+".txt")
|
||||
return path.Join(f.storagePath, dashboardID+".txt")
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package storage // import "github.com/Luzifer/mondash/storage"
|
||||
package storage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/Luzifer/mondash/config"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
|
@ -15,24 +16,26 @@ import (
|
|||
// S3Storage is a storage adapter storing the data into single S3 files
|
||||
type S3Storage struct {
|
||||
s3connection *s3.S3
|
||||
cfg *config.Config
|
||||
bucket string
|
||||
prefix string
|
||||
}
|
||||
|
||||
// NewS3Storage instanciates a new S3Storage
|
||||
func NewS3Storage(cfg *config.Config) *S3Storage {
|
||||
func NewS3Storage(uri *url.URL) *S3Storage {
|
||||
s3connection := s3.New(session.Must(session.NewSession()))
|
||||
return &S3Storage{
|
||||
s3connection: s3connection,
|
||||
cfg: cfg,
|
||||
bucket: uri.Host,
|
||||
prefix: uri.Path,
|
||||
}
|
||||
}
|
||||
|
||||
// Put writes the given data to S3
|
||||
func (s *S3Storage) Put(dashboardID string, data []byte) error {
|
||||
_, err := s.s3connection.PutObject(&s3.PutObjectInput{
|
||||
Bucket: aws.String(s.cfg.S3.Bucket),
|
||||
Bucket: aws.String(s.bucket),
|
||||
ContentType: aws.String("application/json"),
|
||||
Key: aws.String(dashboardID),
|
||||
Key: s.getKey(dashboardID),
|
||||
Body: bytes.NewReader(data),
|
||||
ACL: aws.String("private"),
|
||||
})
|
||||
|
@ -43,8 +46,8 @@ func (s *S3Storage) Put(dashboardID string, data []byte) error {
|
|||
// Get loads the data for the given dashboard from S3
|
||||
func (s *S3Storage) Get(dashboardID string) ([]byte, error) {
|
||||
res, err := s.s3connection.GetObject(&s3.GetObjectInput{
|
||||
Bucket: aws.String(s.cfg.S3.Bucket),
|
||||
Key: aws.String(dashboardID),
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: s.getKey(dashboardID),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -63,8 +66,8 @@ func (s *S3Storage) Get(dashboardID string) ([]byte, error) {
|
|||
// Delete deletes the given dashboard from S3
|
||||
func (s *S3Storage) Delete(dashboardID string) error {
|
||||
_, err := s.s3connection.DeleteObject(&s3.DeleteObjectInput{
|
||||
Bucket: aws.String(s.cfg.S3.Bucket),
|
||||
Key: aws.String(dashboardID),
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: s.getKey(dashboardID),
|
||||
})
|
||||
|
||||
return err
|
||||
|
@ -73,8 +76,8 @@ func (s *S3Storage) Delete(dashboardID string) error {
|
|||
// Exists checks for the existence of the given dashboard
|
||||
func (s *S3Storage) Exists(dashboardID string) (bool, error) {
|
||||
_, err := s.s3connection.HeadObject(&s3.HeadObjectInput{
|
||||
Bucket: aws.String(s.cfg.S3.Bucket),
|
||||
Key: aws.String(dashboardID),
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: s.getKey(dashboardID),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
@ -89,3 +92,8 @@ func (s *S3Storage) Exists(dashboardID string) (bool, error) {
|
|||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s S3Storage) getKey(dashboardID string) *string {
|
||||
p := path.Join(s.prefix, dashboardID)
|
||||
return aws.String(strings.TrimLeft(p, "/"))
|
||||
}
|
||||
|
|
10
strings.go
10
strings.go
|
@ -1,10 +0,0 @@
|
|||
package main
|
||||
|
||||
func stringInSlice(a string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
291
structs.go
291
structs.go
|
@ -2,73 +2,126 @@ package main
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"sort"
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/Luzifer/go_helpers/str"
|
||||
|
||||
"github.com/Luzifer/mondash/storage"
|
||||
)
|
||||
|
||||
const defaultStalenessStatus = "Unknown"
|
||||
const defaultStalenessStatus = metricStatusUnknown
|
||||
|
||||
var errDashboardNotFound = errors.New("Dashboard not found")
|
||||
|
||||
// --- Metric Status ---
|
||||
|
||||
type metricStatus uint
|
||||
|
||||
var metricStatusStringMapping = []string{
|
||||
"OK",
|
||||
"Warning",
|
||||
"Critical",
|
||||
"Unknown",
|
||||
"Total",
|
||||
}
|
||||
|
||||
const (
|
||||
// Nagios status mappings
|
||||
metricStatusOK metricStatus = iota
|
||||
metricStatusWarning
|
||||
metricStatusCritical
|
||||
metricStatusUnknown
|
||||
metricStatusTotal // Only internally used
|
||||
)
|
||||
|
||||
func metricStatusFromString(in string) metricStatus {
|
||||
for i, v := range metricStatusStringMapping {
|
||||
if v == in {
|
||||
return metricStatus(i)
|
||||
}
|
||||
}
|
||||
|
||||
return metricStatusUnknown
|
||||
}
|
||||
|
||||
func (m metricStatus) String() string {
|
||||
return metricStatusStringMapping[m]
|
||||
}
|
||||
|
||||
// --- Dashboard ---
|
||||
|
||||
type dashboard struct {
|
||||
DashboardID string `json:"-"`
|
||||
APIKey string `json:"api_key"`
|
||||
Metrics dashboardMetrics `json:"metrics"`
|
||||
storage storage.Storage
|
||||
DashboardID string `json:"-"`
|
||||
APIKey string `json:"api_key"`
|
||||
Metrics []*dashboardMetric `json:"metrics"`
|
||||
|
||||
storage storage.Storage
|
||||
}
|
||||
|
||||
func loadDashboard(dashid string, store storage.Storage) (*dashboard, error) {
|
||||
data, err := store.Get(dashid)
|
||||
if err != nil {
|
||||
return &dashboard{}, errors.New("Dashboard not found")
|
||||
return nil, errDashboardNotFound
|
||||
}
|
||||
|
||||
tmp := &dashboard{
|
||||
DashboardID: dashid,
|
||||
storage: store,
|
||||
}
|
||||
_ = json.Unmarshal(data, tmp)
|
||||
|
||||
if err := json.Unmarshal(data, tmp); err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to unmarshal dashboard")
|
||||
}
|
||||
|
||||
tmp.migrate() // Do a load-migration, it will be applied on save
|
||||
|
||||
return tmp, nil
|
||||
}
|
||||
|
||||
func (d *dashboard) Save() {
|
||||
func (d *dashboard) Save() error {
|
||||
data, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
log.Printf("Error while marshalling dashboard: %s", err)
|
||||
return
|
||||
return errors.Wrap(err, "Unable to marshal dashboard")
|
||||
}
|
||||
err = d.storage.Put(d.DashboardID, data)
|
||||
if err != nil {
|
||||
log.Printf("Error while storing dashboard: %s", err)
|
||||
|
||||
return errors.Wrap(d.storage.Put(d.DashboardID, data), "Unable to store dashboard")
|
||||
}
|
||||
|
||||
func (d *dashboard) migrate() {
|
||||
// Migrate metadata
|
||||
for _, m := range d.Metrics {
|
||||
if m.Meta.LastUpdate.IsZero() && !m.Meta.MIGLastUpdate.IsZero() {
|
||||
m.Meta.LastUpdate = m.Meta.MIGLastUpdate
|
||||
m.Meta.MIGLastUpdate = time.Time{}
|
||||
}
|
||||
|
||||
if m.Meta.LastOK.IsZero() && !m.Meta.MIGLastOK.IsZero() {
|
||||
m.Meta.LastOK = m.Meta.MIGLastOK
|
||||
m.Meta.MIGLastOK = time.Time{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type dashboardMetrics []*dashboardMetric
|
||||
|
||||
func (a dashboardMetrics) Len() int { return len(a) }
|
||||
func (a dashboardMetrics) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a dashboardMetrics) Less(i, j int) bool {
|
||||
return a[i].Meta.LastUpdate.Before(a[j].Meta.LastUpdate)
|
||||
}
|
||||
// --- Dashboard Metric ---
|
||||
|
||||
type dashboardMetric struct {
|
||||
MetricID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
Value float64 `json:"value,omitifempty"`
|
||||
Expires int64 `json:"expires,omitifempty"`
|
||||
Freshness int64 `json:"freshness,omitifempty"`
|
||||
IgnoreMAD bool `json:"ignore_mad"`
|
||||
HideMAD bool `json:"hide_mad"`
|
||||
HideValue bool `json:"hide_value"`
|
||||
HistoricalData dashboardMetricHistory `json:"history,omitifempty"`
|
||||
Meta dashboardMetricMeta `json:"meta,omitifempty"`
|
||||
StalenessStatus string `json:"staleness_status,omitifempty"`
|
||||
MetricID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
Value float64 `json:"value,omitempty"`
|
||||
Expires int64 `json:"expires,omitempty"`
|
||||
Freshness int64 `json:"freshness,omitempty"`
|
||||
IgnoreMAD bool `json:"ignore_mad"`
|
||||
HideMAD bool `json:"hide_mad"`
|
||||
HideValue bool `json:"hide_value"`
|
||||
HistoricalData []dashboardMetricStatus `json:"history,omitempty"`
|
||||
Meta dashboardMetricMeta `json:"meta,omitempty"`
|
||||
StalenessStatus string `json:"staleness_status,omitempty"`
|
||||
}
|
||||
|
||||
type dashboardMetricStatus struct {
|
||||
|
@ -78,62 +131,27 @@ type dashboardMetricStatus struct {
|
|||
}
|
||||
|
||||
type dashboardMetricMeta struct {
|
||||
LastUpdate time.Time
|
||||
LastOK time.Time
|
||||
PercOK float64
|
||||
PercWarn float64
|
||||
PercCrit float64
|
||||
}
|
||||
LastUpdate time.Time `json:"last_update"`
|
||||
LastOK time.Time `json:"last_ok"`
|
||||
PercOK float64 `json:"perc_ok"`
|
||||
PercWarn float64 `json:"perc_warn"`
|
||||
PercCrit float64 `json:"perc_crit"`
|
||||
|
||||
type dashboardMetricHistory []dashboardMetricStatus
|
||||
MIGLastUpdate time.Time `json:"LastUpdate,omitempty"`
|
||||
MIGLastOK time.Time `json:"LastOK,omitempty"`
|
||||
}
|
||||
|
||||
func newDashboardMetric() *dashboardMetric {
|
||||
return &dashboardMetric{
|
||||
Status: defaultStalenessStatus,
|
||||
Status: defaultStalenessStatus.String(),
|
||||
Expires: 604800,
|
||||
Freshness: 3600,
|
||||
HistoricalData: dashboardMetricHistory{},
|
||||
HistoricalData: []dashboardMetricStatus{},
|
||||
Meta: dashboardMetricMeta{},
|
||||
}
|
||||
}
|
||||
|
||||
func median(values []float64) float64 {
|
||||
sort.Float64s(values)
|
||||
|
||||
if len(values) == 1 {
|
||||
return values[0]
|
||||
}
|
||||
|
||||
// If even, take an average
|
||||
if len(values)%2 == 0 {
|
||||
return 0.5*values[len(values)/2] + 0.5*values[len(values)/2-1]
|
||||
}
|
||||
|
||||
log.Printf("len(values)=%v, len(values)/2=%v\n", len(values), len(values)/2)
|
||||
|
||||
return values[len(values)/2-1]
|
||||
}
|
||||
|
||||
func absoluteValue(value float64) float64 {
|
||||
if value < 0 {
|
||||
value = -value
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func absoluteDeviation(values []float64) []float64 {
|
||||
medianValue := median(values)
|
||||
|
||||
deviation := make([]float64, len(values))
|
||||
|
||||
for i := range values {
|
||||
deviation[i] = absoluteValue(values[i] - medianValue)
|
||||
}
|
||||
|
||||
return deviation
|
||||
}
|
||||
|
||||
func (dm *dashboardMetric) getValueArray() []float64 {
|
||||
func (dm dashboardMetric) getValueArray() []float64 {
|
||||
values := []float64{}
|
||||
|
||||
for _, v := range dm.HistoricalData {
|
||||
|
@ -143,51 +161,73 @@ func (dm *dashboardMetric) getValueArray() []float64 {
|
|||
return values
|
||||
}
|
||||
|
||||
func (dm *dashboardMetric) Median() float64 {
|
||||
func (dm dashboardMetric) Median() float64 {
|
||||
return median(dm.getValueArray())
|
||||
}
|
||||
|
||||
func (dm *dashboardMetric) MedianAbsoluteDeviation() (float64, float64) {
|
||||
func (dm dashboardMetric) MedianAbsoluteDeviation() (float64, float64) {
|
||||
values := dm.getValueArray()
|
||||
medianValue := dm.Median()
|
||||
|
||||
return medianValue, median(absoluteDeviation(values))
|
||||
}
|
||||
|
||||
func (dm *dashboardMetric) MadMultiplier() float64 {
|
||||
func (dm dashboardMetric) MadMultiplier() float64 {
|
||||
medianValue, MAD := dm.MedianAbsoluteDeviation()
|
||||
|
||||
return absoluteValue(dm.Value-medianValue) / MAD
|
||||
}
|
||||
|
||||
func (dm *dashboardMetric) StatisticalStatus() string {
|
||||
mult := dm.MadMultiplier()
|
||||
|
||||
if mult > 4 {
|
||||
return "Critical"
|
||||
} else if mult > 3 {
|
||||
return "Warning"
|
||||
if MAD == 0 {
|
||||
// Edge-case, causes div-by-zero
|
||||
return 1
|
||||
}
|
||||
|
||||
return "OK"
|
||||
return math.Abs(dm.Value-medianValue) / MAD
|
||||
}
|
||||
|
||||
func (dm *dashboardMetric) PreferredStatus() string {
|
||||
if dm.Meta.LastUpdate.Before(time.Now().Add(-1 * time.Duration(dm.Freshness) * time.Second)) {
|
||||
func (dm dashboardMetric) StatisticalStatus() string {
|
||||
mult := dm.MadMultiplier()
|
||||
|
||||
switch {
|
||||
case mult > 4:
|
||||
return "Critical"
|
||||
|
||||
case mult > 3:
|
||||
return "Warning"
|
||||
|
||||
default:
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
|
||||
func (dm dashboardMetric) PreferredStatus() string {
|
||||
// Metric might be stale, return stale status
|
||||
if dm.Meta.LastUpdate.Add(time.Duration(dm.Freshness) * time.Second).Before(time.Now()) {
|
||||
if dm.StalenessStatus == "" {
|
||||
return defaultStalenessStatus
|
||||
return defaultStalenessStatus.String()
|
||||
}
|
||||
return dm.StalenessStatus
|
||||
}
|
||||
|
||||
// If MAD is ignored use given status
|
||||
if dm.IgnoreMAD {
|
||||
return dm.Status
|
||||
}
|
||||
|
||||
// By default use MAD for status
|
||||
return dm.StatisticalStatus()
|
||||
}
|
||||
|
||||
func (dm *dashboardMetric) LabelHistory() []string {
|
||||
func (dm dashboardMetric) HistoricalValueMap() map[int64]float64 {
|
||||
out := map[int64]float64{}
|
||||
|
||||
start := int(math.Max(0, float64(len(dm.HistoricalData)-30)))
|
||||
for _, v := range dm.HistoricalData[start:] {
|
||||
out[v.Time.Unix()] = v.Value
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (dm dashboardMetric) LabelHistory() []string {
|
||||
s := []string{}
|
||||
|
||||
labelStart := len(dm.HistoricalData) - 60
|
||||
|
@ -202,7 +242,7 @@ func (dm *dashboardMetric) LabelHistory() []string {
|
|||
return s
|
||||
}
|
||||
|
||||
func (dm *dashboardMetric) DataHistory() []string {
|
||||
func (dm dashboardMetric) DataHistory() []string {
|
||||
s := []string{}
|
||||
|
||||
dataStart := len(dm.HistoricalData) - 60
|
||||
|
@ -226,43 +266,52 @@ func (dm *dashboardMetric) Update(m *dashboardMetric) {
|
|||
dm.HideMAD = m.HideMAD
|
||||
dm.HideValue = m.HideValue
|
||||
dm.StalenessStatus = m.StalenessStatus
|
||||
|
||||
if m.Expires != 0 {
|
||||
dm.Expires = m.Expires
|
||||
}
|
||||
|
||||
if m.Freshness != 0 {
|
||||
dm.Freshness = m.Freshness
|
||||
}
|
||||
|
||||
dm.HistoricalData = append(dm.HistoricalData, dashboardMetricStatus{
|
||||
Time: time.Now(),
|
||||
Status: m.Status,
|
||||
Value: m.Value,
|
||||
})
|
||||
|
||||
countStatus := make(map[string]float64)
|
||||
countStatus := make(map[metricStatus]float64)
|
||||
|
||||
expired := time.Now().Add(time.Duration(dm.Expires*-1) * time.Second)
|
||||
tmp := dashboardMetricHistory{}
|
||||
tmp := []dashboardMetricStatus{}
|
||||
|
||||
for _, s := range dm.HistoricalData {
|
||||
if s.Time.After(expired) {
|
||||
statusVal := metricStatusFromString(s.Status)
|
||||
|
||||
tmp = append(tmp, s)
|
||||
countStatus[s.Status] = countStatus[s.Status] + 1
|
||||
countStatus["Total"] = countStatus["Total"] + 1
|
||||
if dm.Meta.LastOK.Before(s.Time) && s.Status == "OK" {
|
||||
|
||||
countStatus[statusVal] = countStatus[statusVal] + 1
|
||||
countStatus[metricStatusTotal] = countStatus[metricStatusTotal] + 1
|
||||
|
||||
if dm.Meta.LastOK.Before(s.Time) && statusVal == metricStatusOK {
|
||||
dm.Meta.LastOK = s.Time
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dm.HistoricalData = tmp
|
||||
|
||||
dm.Meta.LastUpdate = time.Now()
|
||||
if countStatus["Total"] > 0 {
|
||||
dm.Meta.PercCrit = countStatus["Critical"] / countStatus["Total"] * 100
|
||||
dm.Meta.PercWarn = countStatus["Warning"] / countStatus["Total"] * 100
|
||||
dm.Meta.PercOK = countStatus["OK"] / countStatus["Total"] * 100
|
||||
if countStatus[metricStatusTotal] > 0 {
|
||||
dm.Meta.PercCrit = countStatus[metricStatusCritical] / countStatus[metricStatusTotal] * 100
|
||||
dm.Meta.PercWarn = countStatus[metricStatusWarning] / countStatus[metricStatusTotal] * 100
|
||||
dm.Meta.PercOK = countStatus[metricStatusOK] / countStatus[metricStatusTotal] * 100
|
||||
}
|
||||
}
|
||||
|
||||
func (dm *dashboardMetric) IsValid() (bool, string) {
|
||||
func (dm dashboardMetric) IsValid() (bool, string) {
|
||||
if dm.Expires > 604800 || dm.Expires < 0 {
|
||||
return false, "Expires not in range 0 < x < 640800"
|
||||
}
|
||||
|
@ -271,7 +320,7 @@ func (dm *dashboardMetric) IsValid() (bool, string) {
|
|||
return false, "Freshness not in range 0 < x < 640800"
|
||||
}
|
||||
|
||||
if !stringInSlice(dm.Status, []string{"OK", "Warning", "Critical", "Unknowm"}) {
|
||||
if !str.StringInSlice(dm.Status, []string{"OK", "Warning", "Critical", "Unknowm"}) {
|
||||
return false, "Status not allowed"
|
||||
}
|
||||
|
||||
|
@ -283,11 +332,11 @@ func (dm *dashboardMetric) IsValid() (bool, string) {
|
|||
}
|
||||
|
||||
type historyBarSegment struct {
|
||||
Duration time.Duration
|
||||
End time.Time
|
||||
Percentage float64
|
||||
Start time.Time
|
||||
Status string
|
||||
Duration time.Duration `json:"duration"`
|
||||
End time.Time `json:"end"`
|
||||
Percentage float64 `json:"percentage"`
|
||||
Start time.Time `json:"start"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (dm dashboardMetric) GetHistoryBar() []historyBarSegment {
|
||||
|
@ -300,7 +349,7 @@ func (dm dashboardMetric) GetHistoryBar() []historyBarSegment {
|
|||
)
|
||||
|
||||
for _, point = range dm.HistoricalData {
|
||||
if point.Status == status {
|
||||
if metricStatusFromString(point.Status) == status {
|
||||
segLength++
|
||||
continue
|
||||
}
|
||||
|
@ -312,14 +361,14 @@ func (dm dashboardMetric) GetHistoryBar() []historyBarSegment {
|
|||
End: point.Time,
|
||||
Percentage: float64(segLength) / float64(len(dm.HistoricalData)),
|
||||
Start: segStart,
|
||||
Status: status,
|
||||
Status: status.String(),
|
||||
})
|
||||
}
|
||||
|
||||
// Start a new segment
|
||||
segLength = 1
|
||||
segStart = point.Time
|
||||
status = point.Status
|
||||
status = metricStatusFromString(point.Status)
|
||||
}
|
||||
|
||||
segments = append(segments, historyBarSegment{
|
||||
|
@ -327,7 +376,7 @@ func (dm dashboardMetric) GetHistoryBar() []historyBarSegment {
|
|||
End: point.Time,
|
||||
Percentage: float64(segLength) / float64(len(dm.HistoricalData)),
|
||||
Start: segStart,
|
||||
Status: status,
|
||||
Status: status.String(),
|
||||
})
|
||||
|
||||
return segments
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>MonDash - Dashboard</title>
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap-theme.min.css"
|
||||
integrity="sha256-ZT4HPpdCOt2lvDkXokHuhJfdOKSPFLzeAJik5U/Q+l4=" crossorigin="anonymous" />
|
||||
|
||||
<!-- Chartist -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.0/chartist.min.css"
|
||||
integrity="sha256-Te9+aTaL9j0U5PzLhtAHt+SXlgIT8KT9VkyOZn68hak=" crossorigin="anonymous" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.0/chartist.min.js"
|
||||
integrity="sha256-UzffRueYhyZDw8Cj39UCnnggvBfa1fPcDQ0auvCbvCc=" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<script>
|
||||
function timeConverter(UNIX_timestamp){
|
||||
var a = new Date(UNIX_timestamp*1000);
|
||||
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
|
||||
var year = a.getFullYear();
|
||||
var month = months[a.getMonth()];
|
||||
var date = a.getDate();
|
||||
var hour = a.getHours();
|
||||
var min = a.getMinutes();
|
||||
var sec = a.getSeconds();
|
||||
var time = date + ' ' + month + ' ' + year + ' ' + hour + ':' + min + ':' + sec ;
|
||||
return time;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="/">MonDash</a>
|
||||
</div><!-- /.navbar-header -->
|
||||
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="http://docs.mondash.apiary.io/" target="_blank">API Docs</a></li>
|
||||
</ul><!-- /.navbar-right -->
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/create">Get your own dashboard</a></li>
|
||||
</ul><!-- /.navbar-right -->
|
||||
</div><!-- /.navbar-collapse -->
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
{% if dashid == "welcome" %}
|
||||
<div class="row">
|
||||
<div class="jumbotron text-center">
|
||||
<h1>Welcome to MonDash!</h1>
|
||||
<p>You're currently seeing a demo dashboard updated with random numbers below. To get started read the <a href="http://docs.mondash.apiary.io/" target="_blank">API documentation</a> and create your own dashboard by clicking the button in the upper right hand corner…
|
||||
<p>If you have any questions about this project don't hesitate to ask <a href="https://ahlers.me/" target="_blank">Knut</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if metrics|length == 0 and dashid != "welcome" %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3 text-center">
|
||||
<p>Welcome to your new dashboard. Your API-key is:</p>
|
||||
<pre>{{ apikey }}</pre>
|
||||
<p>After you sent your first metric you can reach your dashboard here:</p>
|
||||
<a href="{{ baseurl }}/{{ dashid }}">{{ baseurl }}/{{ dashid }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{% for metric in metrics %}
|
||||
{% if metric.PreferredStatus == "OK" %}
|
||||
<div class="row alert alert-success">
|
||||
{% elif metric.PreferredStatus == "Warning" %}
|
||||
<div class="row alert alert-warning">
|
||||
{% elif metric.PreferredStatus == "Critical" %}
|
||||
<div class="row alert alert-danger">
|
||||
{% else %}
|
||||
<div class="row alert alert-info">
|
||||
{% endif %}
|
||||
<div class="col-md-9">
|
||||
<h4>{{ metric.Title }}</h4>
|
||||
<p>{{ metric.Description }}</p>
|
||||
{% if !metric.HideValue %}
|
||||
<span>
|
||||
{% if metric.Status == "OK" %}
|
||||
<span class="label label-success">Current Value: {{ metric.Value }}</span>
|
||||
{% elif metric.Status == "Warning" %}
|
||||
<span class="label label-warning">Current Value: {{ metric.Value }}</span>
|
||||
{% elif metric.Status == "Critical" %}
|
||||
<span class="label label-danger">Current Value: {{ metric.Value }}</span>
|
||||
{% else %}
|
||||
<span class="label label-info">Current Value: {{ metric.Value }}</span>
|
||||
{% endif %}
|
||||
{% if !metric.HideMAD %}
|
||||
<abbr title="Median Absolute Deviation">MAD</abbr>: {{ metric.MadMultiplier }} above the Median ({{ metric.Median }})
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if !metric.HideMAD %}
|
||||
<div class="ct-chart {{metric.MetricID}} .ct-double-octave"></div>
|
||||
<script>
|
||||
var data = {
|
||||
// A labels array that can contain any sort of values
|
||||
labels: [{{ metric.LabelHistory|lastNItems:"60"|join:"," }}],
|
||||
// Our series array that contains series objects or in this case series data arrays
|
||||
series: [[{{ metric.DataHistory|lastNItems:"60"|join:"," }}]]
|
||||
};
|
||||
|
||||
for (var i = 0; i < data.labels.length; i++) {
|
||||
data.labels[i] = timeConverter(data.labels[i]);
|
||||
}
|
||||
|
||||
new Chartist.Line('.{{metric.MetricID}}', data);
|
||||
</script>
|
||||
{% endif %}
|
||||
<small>
|
||||
Updated {{ metric.Meta.LastUpdate|naturaltime}}
|
||||
{% if metric.Status != "OK" %}
|
||||
/ Last ok {{ metric.Meta.LastOK|naturaltime }}
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-3 hidden-xs">
|
||||
<div class="progress">
|
||||
{% for seg in metric.GetHistoryBar %}
|
||||
<div class="progress-bar
|
||||
{% if seg.Status == "OK" %}progress-bar-success
|
||||
{% elif seg.Status == "Warning" %}progress-bar-warning
|
||||
{% elif seg.Status == "Critical" %}progress-bar-danger
|
||||
{% else %}progress-bar-info
|
||||
{% endif %}"
|
||||
style="width: {{ seg.Percentage * 100 }}%"
|
||||
data-toggle="tooltip" data-placement="bottom"
|
||||
title="Start: {{ seg.Start|time:"2006-01-02 15:04:05" }}<br>End: {{ seg.End|time:"2006-01-02 15:04:05" }}"
|
||||
>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"
|
||||
integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
|
||||
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"
|
||||
integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip({
|
||||
container: 'body',
|
||||
html: true,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
202
vendor/github.com/Luzifer/go_helpers/LICENSE
generated
vendored
Normal file
202
vendor/github.com/Luzifer/go_helpers/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2016- Knut Ahlers <knut@ahlers.me>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
37
vendor/github.com/Luzifer/go_helpers/accessLogger/accessLogger.go
generated
vendored
Normal file
37
vendor/github.com/Luzifer/go_helpers/accessLogger/accessLogger.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
package accessLogger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type AccessLogResponseWriter struct {
|
||||
StatusCode int
|
||||
Size int
|
||||
|
||||
http.ResponseWriter
|
||||
}
|
||||
|
||||
func New(res http.ResponseWriter) *AccessLogResponseWriter {
|
||||
return &AccessLogResponseWriter{
|
||||
StatusCode: 200,
|
||||
Size: 0,
|
||||
ResponseWriter: res,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AccessLogResponseWriter) Write(out []byte) (int, error) {
|
||||
s, err := a.ResponseWriter.Write(out)
|
||||
a.Size += s
|
||||
return s, err
|
||||
}
|
||||
|
||||
func (a *AccessLogResponseWriter) WriteHeader(code int) {
|
||||
a.StatusCode = code
|
||||
a.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
func (a *AccessLogResponseWriter) HTTPResponseType() string {
|
||||
return fmt.Sprintf("%cxx", strconv.FormatInt(int64(a.StatusCode), 10)[0])
|
||||
}
|
55
vendor/github.com/Luzifer/go_helpers/http/digest.go
generated
vendored
Normal file
55
vendor/github.com/Luzifer/go_helpers/http/digest.go
generated
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Luzifer/go_helpers/str"
|
||||
)
|
||||
|
||||
func GetDigestAuth(resp *http.Response, method, requestPath, user, password string) string {
|
||||
params := map[string]string{}
|
||||
for _, part := range strings.Split(resp.Header.Get("Www-Authenticate"), " ") {
|
||||
if !strings.Contains(part, `="`) {
|
||||
continue
|
||||
}
|
||||
spl := strings.Split(strings.Trim(part, " ,"), "=")
|
||||
if !str.StringInSlice(spl[0], []string{"nonce", "realm", "qop"}) {
|
||||
continue
|
||||
}
|
||||
params[spl[0]] = strings.Trim(spl[1], `"`)
|
||||
}
|
||||
|
||||
b := make([]byte, 8)
|
||||
io.ReadFull(rand.Reader, b)
|
||||
|
||||
params["cnonce"] = fmt.Sprintf("%x", b)
|
||||
params["nc"] = "1"
|
||||
params["uri"] = requestPath
|
||||
params["username"] = user
|
||||
params["response"] = getMD5([]string{
|
||||
getMD5([]string{params["username"], params["realm"], password}),
|
||||
params["nonce"],
|
||||
params["nc"],
|
||||
params["cnonce"],
|
||||
params["qop"],
|
||||
getMD5([]string{method, requestPath}),
|
||||
})
|
||||
|
||||
authParts := []string{}
|
||||
for k, v := range params {
|
||||
authParts = append(authParts, fmt.Sprintf("%s=%q", k, v))
|
||||
}
|
||||
return "Digest " + strings.Join(authParts, ", ")
|
||||
}
|
||||
|
||||
func getMD5(in []string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(strings.Join(in, ":")))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
47
vendor/github.com/Luzifer/go_helpers/http/gzip.go
generated
vendored
Normal file
47
vendor/github.com/Luzifer/go_helpers/http/gzip.go
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type gzipResponseWriter struct {
|
||||
io.Writer
|
||||
http.ResponseWriter
|
||||
}
|
||||
|
||||
func (w gzipResponseWriter) Write(b []byte) (int, error) {
|
||||
return w.Writer.Write(b)
|
||||
}
|
||||
|
||||
// GzipHandler wraps an http.Handler and gzips responses if the client supports it
|
||||
func GzipHandler(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
gz := gzip.NewWriter(w)
|
||||
defer gz.Close()
|
||||
gzw := gzipResponseWriter{Writer: gz, ResponseWriter: w}
|
||||
handler.ServeHTTP(gzw, r)
|
||||
})
|
||||
}
|
||||
|
||||
// GzipFunc wraps an http.HandlerFunc and gzips responses if the client supports it
|
||||
func GzipFunc(f http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
||||
f(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
gz := gzip.NewWriter(w)
|
||||
defer gz.Close()
|
||||
gzw := gzipResponseWriter{Writer: gz, ResponseWriter: w}
|
||||
f(gzw, r)
|
||||
}
|
||||
}
|
57
vendor/github.com/Luzifer/go_helpers/http/logHandler.go
generated
vendored
Normal file
57
vendor/github.com/Luzifer/go_helpers/http/logHandler.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Luzifer/go_helpers/accessLogger"
|
||||
)
|
||||
|
||||
type HTTPLogHandler struct {
|
||||
Handler http.Handler
|
||||
TrustedIPHeaders []string
|
||||
}
|
||||
|
||||
func NewHTTPLogHandler(h http.Handler) http.Handler {
|
||||
return HTTPLogHandler{
|
||||
Handler: h,
|
||||
TrustedIPHeaders: []string{"X-Forwarded-For", "RemoteAddr", "X-Real-IP"},
|
||||
}
|
||||
}
|
||||
|
||||
func (l HTTPLogHandler) ServeHTTP(res http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
ares := accessLogger.New(res)
|
||||
|
||||
l.Handler.ServeHTTP(ares, r)
|
||||
|
||||
path := r.URL.Path
|
||||
if q := r.URL.Query().Encode(); len(q) > 0 {
|
||||
path = path + "?" + q
|
||||
}
|
||||
|
||||
log.Printf("%s - \"%s %s\" %d %d \"%s\" \"%s\" %s",
|
||||
l.findIP(r),
|
||||
r.Method,
|
||||
path,
|
||||
ares.StatusCode,
|
||||
ares.Size,
|
||||
r.Header.Get("Referer"),
|
||||
r.Header.Get("User-Agent"),
|
||||
time.Since(start),
|
||||
)
|
||||
}
|
||||
|
||||
func (l HTTPLogHandler) findIP(r *http.Request) string {
|
||||
remoteAddr := strings.SplitN(r.RemoteAddr, ":", 2)[0]
|
||||
|
||||
for _, hdr := range l.TrustedIPHeaders {
|
||||
if value := r.Header.Get(hdr); value != "" {
|
||||
return strings.SplitN(value, ",", 2)[0]
|
||||
}
|
||||
}
|
||||
|
||||
return remoteAddr
|
||||
}
|
21
vendor/github.com/Luzifer/go_helpers/str/slice.go
generated
vendored
Normal file
21
vendor/github.com/Luzifer/go_helpers/str/slice.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
package str
|
||||
|
||||
// AppendIfMissing adds a string to a slice when it's not present yet
|
||||
func AppendIfMissing(slice []string, s string) []string {
|
||||
for _, e := range slice {
|
||||
if e == s {
|
||||
return slice
|
||||
}
|
||||
}
|
||||
return append(slice, s)
|
||||
}
|
||||
|
||||
// StringInSlice checks for the existence of a string in the slice
|
||||
func StringInSlice(a string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
8
vendor/github.com/Luzifer/rconfig/.travis.yml
generated
vendored
8
vendor/github.com/Luzifer/rconfig/.travis.yml
generated
vendored
|
@ -1,8 +0,0 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.6
|
||||
- 1.7
|
||||
- tip
|
||||
|
||||
script: go test -v -race -cover ./...
|
9
vendor/github.com/Luzifer/rconfig/History.md
generated
vendored
9
vendor/github.com/Luzifer/rconfig/History.md
generated
vendored
|
@ -1,9 +0,0 @@
|
|||
# 1.2.0 / 2017-06-19
|
||||
|
||||
* Add ParseAndValidate method
|
||||
|
||||
# 1.1.0 / 2016-06-28
|
||||
|
||||
* Support time.Duration config parameters
|
||||
* Added goreportcard badge
|
||||
* Added testcase for using bool with ENV and default
|
209
vendor/github.com/Luzifer/rconfig/LICENSE
generated
vendored
209
vendor/github.com/Luzifer/rconfig/LICENSE
generated
vendored
|
@ -1,13 +1,202 @@
|
|||
Copyright 2015 Knut Ahlers <knut@ahlers.me>
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015- Knut Ahlers <knut@ahlers.me>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
87
vendor/github.com/Luzifer/rconfig/README.md
generated
vendored
87
vendor/github.com/Luzifer/rconfig/README.md
generated
vendored
|
@ -1,87 +0,0 @@
|
|||
[![Build Status](https://travis-ci.org/Luzifer/rconfig.svg?branch=master)](https://travis-ci.org/Luzifer/rconfig)
|
||||
[![License: Apache v2.0](https://badge.luzifer.io/v1/badge?color=5d79b5&title=license&text=Apache+v2.0)](http://www.apache.org/licenses/LICENSE-2.0)
|
||||
[![Documentation](https://badge.luzifer.io/v1/badge?title=godoc&text=reference)](https://godoc.org/github.com/Luzifer/rconfig)
|
||||
[![Go Report](http://goreportcard.com/badge/Luzifer/rconfig)](http://goreportcard.com/report/Luzifer/rconfig)
|
||||
|
||||
## Description
|
||||
|
||||
> Package rconfig implements a CLI configuration reader with struct-embedded defaults, environment variables and posix compatible flag parsing using the [pflag](https://github.com/spf13/pflag) library.
|
||||
|
||||
## Installation
|
||||
|
||||
Install by running:
|
||||
|
||||
```
|
||||
go get -u github.com/Luzifer/rconfig
|
||||
```
|
||||
|
||||
OR fetch a specific version:
|
||||
|
||||
```
|
||||
go get -u gopkg.in/luzifer/rconfig.v1
|
||||
```
|
||||
|
||||
Run tests by running:
|
||||
|
||||
```
|
||||
go test -v -race -cover github.com/Luzifer/rconfig
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
A very simple usecase is to just configure a struct inside the vars section of your `main.go` and to parse the commandline flags from the `main()` function:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Luzifer/rconfig"
|
||||
)
|
||||
|
||||
var (
|
||||
cfg = struct {
|
||||
Username string `default:"unknown" flag:"user" description:"Your name"`
|
||||
Details struct {
|
||||
Age int `default:"25" flag:"age" env:"age" description:"Your age"`
|
||||
}
|
||||
}{}
|
||||
)
|
||||
|
||||
func main() {
|
||||
rconfig.Parse(&cfg)
|
||||
|
||||
fmt.Printf("Hello %s, happy birthday for your %dth birthday.",
|
||||
cfg.Username,
|
||||
cfg.Details.Age)
|
||||
}
|
||||
```
|
||||
|
||||
### Provide variable defaults by using a file
|
||||
|
||||
Given you have a file `~/.myapp.yml` containing some secrets or usernames (for the example below username is assumed to be "luzifer") as a default configuration for your application you can use this source code to load the defaults from that file using the `vardefault` tag in your configuration struct.
|
||||
|
||||
The order of the directives (lower number = higher precedence):
|
||||
|
||||
1. Flags provided in command line
|
||||
1. Environment variables
|
||||
1. Variable defaults (`vardefault` tag in the struct)
|
||||
1. `default` tag in the struct
|
||||
|
||||
```go
|
||||
var cfg = struct {
|
||||
Username string `vardefault:"username" flag:"username" description:"Your username"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
rconfig.SetVariableDefaults(rconfig.VarDefaultsFromYAMLFile("~/.myapp.yml"))
|
||||
rconfig.Parse(&cfg)
|
||||
|
||||
fmt.Printf("Username = %s", cfg.Username)
|
||||
// Output: Username = luzifer
|
||||
}
|
||||
```
|
||||
|
||||
## More info
|
||||
|
||||
You can see the full reference documentation of the rconfig package [at godoc.org](https://godoc.org/github.com/Luzifer/rconfig), or through go's standard documentation system by running `godoc -http=:6060` and browsing to [http://localhost:6060/pkg/github.com/Luzifer/rconfig](http://localhost:6060/pkg/github.com/Luzifer/rconfig) after installation.
|
64
vendor/github.com/Luzifer/rconfig/autoenv.go
generated
vendored
Normal file
64
vendor/github.com/Luzifer/rconfig/autoenv.go
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
package rconfig
|
||||
|
||||
import "strings"
|
||||
|
||||
type characterClass [2]rune
|
||||
|
||||
func (c characterClass) Contains(r rune) bool {
|
||||
return c[0] <= r && c[1] >= r
|
||||
}
|
||||
|
||||
type characterClasses []characterClass
|
||||
|
||||
func (c characterClasses) Contains(r rune) bool {
|
||||
for _, cc := range c {
|
||||
if cc.Contains(r) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
charGroupUpperLetter = characterClass{'A', 'Z'}
|
||||
charGroupLowerLetter = characterClass{'a', 'z'}
|
||||
charGroupNumber = characterClass{'0', '9'}
|
||||
charGroupLowerNumber = characterClasses{charGroupLowerLetter, charGroupNumber}
|
||||
)
|
||||
|
||||
func deriveEnvVarName(s string) string {
|
||||
var (
|
||||
words []string
|
||||
word []rune
|
||||
)
|
||||
|
||||
for _, l := range s {
|
||||
switch {
|
||||
case charGroupUpperLetter.Contains(l):
|
||||
if len(word) > 0 && charGroupLowerNumber.Contains(word[len(word)-1]) {
|
||||
words = append(words, string(word))
|
||||
word = []rune{}
|
||||
}
|
||||
word = append(word, l)
|
||||
|
||||
case charGroupLowerLetter.Contains(l):
|
||||
if len(word) > 1 && charGroupUpperLetter.Contains(word[len(word)-1]) {
|
||||
words = append(words, string(word[0:len(word)-1]))
|
||||
word = word[len(word)-1:]
|
||||
}
|
||||
word = append(word, l)
|
||||
|
||||
case charGroupNumber.Contains(l):
|
||||
word = append(word, l)
|
||||
|
||||
default:
|
||||
if len(word) > 0 {
|
||||
words = append(words, string(word))
|
||||
}
|
||||
word = []rune{}
|
||||
}
|
||||
}
|
||||
words = append(words, string(word))
|
||||
|
||||
return strings.ToUpper(strings.Join(words, "_"))
|
||||
}
|
70
vendor/github.com/Luzifer/rconfig/bool_test.go
generated
vendored
70
vendor/github.com/Luzifer/rconfig/bool_test.go
generated
vendored
|
@ -1,70 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing bool parsing", func() {
|
||||
type t struct {
|
||||
Test1 bool `default:"true"`
|
||||
Test2 bool `default:"false" flag:"test2"`
|
||||
Test3 bool `default:"true" flag:"test3,t"`
|
||||
Test4 bool `flag:"test4"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--test2",
|
||||
"-t",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test1).To(Equal(true))
|
||||
Expect(cfg.Test2).To(Equal(true))
|
||||
Expect(cfg.Test3).To(Equal(true))
|
||||
Expect(cfg.Test4).To(Equal(false))
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("Testing to set bool from ENV with default", func() {
|
||||
type t struct {
|
||||
Test1 bool `default:"true" env:"TEST1"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
os.Unsetenv("TEST1")
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test1).To(Equal(true))
|
||||
})
|
||||
})
|
132
vendor/github.com/Luzifer/rconfig/config.go
generated
vendored
132
vendor/github.com/Luzifer/rconfig/config.go
generated
vendored
|
@ -16,9 +16,25 @@ import (
|
|||
validator "gopkg.in/validator.v2"
|
||||
)
|
||||
|
||||
type afterFunc func() error
|
||||
|
||||
var (
|
||||
autoEnv bool
|
||||
fs *pflag.FlagSet
|
||||
variableDefaults map[string]string
|
||||
|
||||
timeParserFormats = []string{
|
||||
// Default constants
|
||||
time.RFC3339Nano, time.RFC3339,
|
||||
time.RFC1123Z, time.RFC1123,
|
||||
time.RFC822Z, time.RFC822,
|
||||
time.RFC850, time.RubyDate, time.UnixDate, time.ANSIC,
|
||||
"2006-01-02 15:04:05.999999999 -0700 MST",
|
||||
// More uncommon time formats
|
||||
"2006-01-02 15:04:05", "2006-01-02 15:04:05Z07:00", // Simplified ISO time format
|
||||
"01/02/2006 15:04:05", "01/02/2006 15:04:05Z07:00", // US time format
|
||||
"02.01.2006 15:04:05", "02.01.2006 15:04:05Z07:00", // DE time format
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -60,6 +76,18 @@ func Args() []string {
|
|||
return fs.Args()
|
||||
}
|
||||
|
||||
// AddTimeParserFormats adds custom formats to parse time.Time fields
|
||||
func AddTimeParserFormats(f ...string) {
|
||||
timeParserFormats = append(timeParserFormats, f...)
|
||||
}
|
||||
|
||||
// AutoEnv enables or disables automated env variable guessing. If no `env` struct
|
||||
// tag was set and AutoEnv is enabled the env variable name is derived from the
|
||||
// name of the field: `MyFieldName` will get `MY_FIELD_NAME`
|
||||
func AutoEnv(enable bool) {
|
||||
autoEnv = enable
|
||||
}
|
||||
|
||||
// Usage prints a basic usage with the corresponding defaults for the flags to
|
||||
// os.Stdout. The defaults are derived from the `default` struct-tag and the ENV.
|
||||
func Usage() {
|
||||
|
@ -89,22 +117,37 @@ func parse(in interface{}, args []string) error {
|
|||
}
|
||||
|
||||
fs = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
|
||||
if err := execTags(in, fs); err != nil {
|
||||
afterFuncs, err := execTags(in, fs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fs.Parse(args)
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if afterFuncs != nil {
|
||||
for _, f := range afterFuncs {
|
||||
if err := f(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func execTags(in interface{}, fs *pflag.FlagSet) error {
|
||||
func execTags(in interface{}, fs *pflag.FlagSet) ([]afterFunc, error) {
|
||||
if reflect.TypeOf(in).Kind() != reflect.Ptr {
|
||||
return errors.New("Calling parser with non-pointer")
|
||||
return nil, errors.New("Calling parser with non-pointer")
|
||||
}
|
||||
|
||||
if reflect.ValueOf(in).Elem().Kind() != reflect.Struct {
|
||||
return errors.New("Calling parser with pointer to non-struct")
|
||||
return nil, errors.New("Calling parser with pointer to non-struct")
|
||||
}
|
||||
|
||||
afterFuncs := []afterFunc{}
|
||||
|
||||
st := reflect.ValueOf(in).Elem()
|
||||
for i := 0; i < st.NumField(); i++ {
|
||||
valField := st.Field(i)
|
||||
|
@ -116,7 +159,7 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
}
|
||||
|
||||
value := varDefault(typeField.Tag.Get("vardefault"), typeField.Tag.Get("default"))
|
||||
value = envDefault(typeField.Tag.Get("env"), value)
|
||||
value = envDefault(typeField, value)
|
||||
parts := strings.Split(typeField.Tag.Get("flag"), ",")
|
||||
|
||||
switch typeField.Type {
|
||||
|
@ -126,7 +169,7 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
if value == "" {
|
||||
v = time.Duration(0)
|
||||
} else {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,6 +183,53 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
valField.Set(reflect.ValueOf(v))
|
||||
}
|
||||
continue
|
||||
|
||||
case reflect.TypeOf(time.Time{}):
|
||||
var sVar string
|
||||
|
||||
if typeField.Tag.Get("flag") != "" {
|
||||
if len(parts) == 1 {
|
||||
fs.StringVar(&sVar, parts[0], value, typeField.Tag.Get("description"))
|
||||
} else {
|
||||
fs.StringVarP(&sVar, parts[0], parts[1], value, typeField.Tag.Get("description"))
|
||||
}
|
||||
} else {
|
||||
sVar = value
|
||||
}
|
||||
|
||||
afterFuncs = append(afterFuncs, func(valField reflect.Value, sVar *string) func() error {
|
||||
return func() error {
|
||||
if *sVar == "" {
|
||||
// No time, no problem
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check whether we could have a timestamp
|
||||
if ts, err := strconv.ParseInt(*sVar, 10, 64); err == nil {
|
||||
t := time.Unix(ts, 0)
|
||||
valField.Set(reflect.ValueOf(t))
|
||||
return nil
|
||||
}
|
||||
|
||||
// We haven't so lets walk through possible time formats
|
||||
matched := false
|
||||
for _, tf := range timeParserFormats {
|
||||
if t, err := time.Parse(tf, *sVar); err == nil {
|
||||
matched = true
|
||||
valField.Set(reflect.ValueOf(t))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if !matched {
|
||||
return fmt.Errorf("Value %q did not match expected time formats", *sVar)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}(valField, &sVar))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
switch typeField.Type.Kind() {
|
||||
|
@ -172,7 +262,7 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
if value == "" {
|
||||
vt = 0
|
||||
} else {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if typeField.Tag.Get("flag") != "" {
|
||||
|
@ -187,7 +277,7 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
if value == "" {
|
||||
vt = 0
|
||||
} else {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if typeField.Tag.Get("flag") != "" {
|
||||
|
@ -202,7 +292,7 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
if value == "" {
|
||||
vt = 0.0
|
||||
} else {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if typeField.Tag.Get("flag") != "" {
|
||||
|
@ -212,9 +302,11 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
}
|
||||
|
||||
case reflect.Struct:
|
||||
if err := execTags(valField.Addr().Interface(), fs); err != nil {
|
||||
return err
|
||||
afs, err := execTags(valField.Addr().Interface(), fs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
afterFuncs = append(afterFuncs, afs...)
|
||||
|
||||
case reflect.Slice:
|
||||
switch typeField.Type.Elem().Kind() {
|
||||
|
@ -223,7 +315,7 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
for _, v := range strings.Split(value, ",") {
|
||||
it, err := strconv.ParseInt(strings.TrimSpace(v), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
def = append(def, int(it))
|
||||
}
|
||||
|
@ -237,7 +329,10 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
if len(del) == 0 {
|
||||
del = ","
|
||||
}
|
||||
def := strings.Split(value, del)
|
||||
var def = []string{}
|
||||
if value != "" {
|
||||
def = strings.Split(value, del)
|
||||
}
|
||||
if len(parts) == 1 {
|
||||
fs.StringSliceVar(valField.Addr().Interface().(*[]string), parts[0], def, typeField.Tag.Get("description"))
|
||||
} else {
|
||||
|
@ -247,7 +342,7 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return afterFuncs, nil
|
||||
}
|
||||
|
||||
func registerFlagFloat(t reflect.Kind, fs *pflag.FlagSet, field interface{}, parts []string, vt float64, desc string) {
|
||||
|
@ -331,9 +426,14 @@ func registerFlagUint(t reflect.Kind, fs *pflag.FlagSet, field interface{}, part
|
|||
}
|
||||
}
|
||||
|
||||
func envDefault(env, def string) string {
|
||||
func envDefault(field reflect.StructField, def string) string {
|
||||
value := def
|
||||
|
||||
env := field.Tag.Get("env")
|
||||
if env == "" && autoEnv {
|
||||
env = deriveEnvVarName(field.Name)
|
||||
}
|
||||
|
||||
if env != "" {
|
||||
if e := os.Getenv(env); e != "" {
|
||||
value = e
|
||||
|
|
41
vendor/github.com/Luzifer/rconfig/duration_test.go
generated
vendored
41
vendor/github.com/Luzifer/rconfig/duration_test.go
generated
vendored
|
@ -1,41 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Duration", func() {
|
||||
type t struct {
|
||||
Test time.Duration `flag:"duration"`
|
||||
TestS time.Duration `flag:"other-duration,o"`
|
||||
TestDef time.Duration `default:"30h"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--duration=23s", "-o", "45m",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal(23 * time.Second))
|
||||
Expect(cfg.TestS).To(Equal(45 * time.Minute))
|
||||
|
||||
Expect(cfg.TestDef).To(Equal(30 * time.Hour))
|
||||
})
|
||||
})
|
56
vendor/github.com/Luzifer/rconfig/errors_test.go
generated
vendored
56
vendor/github.com/Luzifer/rconfig/errors_test.go
generated
vendored
|
@ -1,56 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing errors", func() {
|
||||
|
||||
It("should not accept string as int", func() {
|
||||
Expect(parse(&struct {
|
||||
A int `default:"a"`
|
||||
}{}, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept string as float", func() {
|
||||
Expect(parse(&struct {
|
||||
A float32 `default:"a"`
|
||||
}{}, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept string as uint", func() {
|
||||
Expect(parse(&struct {
|
||||
A uint `default:"a"`
|
||||
}{}, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept string as uint in sub-struct", func() {
|
||||
Expect(parse(&struct {
|
||||
B struct {
|
||||
A uint `default:"a"`
|
||||
}
|
||||
}{}, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept string slice as int slice", func() {
|
||||
Expect(parse(&struct {
|
||||
A []int `default:"a,bn"`
|
||||
}{}, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept variables not being pointers", func() {
|
||||
cfg := struct {
|
||||
A string `default:"a"`
|
||||
}{}
|
||||
|
||||
Expect(parse(cfg, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should not accept variables not being pointers to structs", func() {
|
||||
cfg := "test"
|
||||
|
||||
Expect(parse(cfg, []string{})).To(HaveOccurred())
|
||||
})
|
||||
|
||||
})
|
37
vendor/github.com/Luzifer/rconfig/example_test.go
generated
vendored
37
vendor/github.com/Luzifer/rconfig/example_test.go
generated
vendored
|
@ -1,37 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ExampleParse() {
|
||||
// We're building an example configuration with a sub-struct to be filled
|
||||
// by the Parse command.
|
||||
config := struct {
|
||||
Username string `default:"unknown" flag:"user,u" description:"Your name"`
|
||||
Details struct {
|
||||
Age int `default:"25" flag:"age" description:"Your age"`
|
||||
}
|
||||
}{}
|
||||
|
||||
// To have more relieable results we're setting os.Args to a known value.
|
||||
// In real-life use cases you wouldn't do this but parse the original
|
||||
// commandline arguments.
|
||||
os.Args = []string{
|
||||
"example",
|
||||
"--user=Luzifer",
|
||||
}
|
||||
|
||||
Parse(&config)
|
||||
|
||||
fmt.Printf("Hello %s, happy birthday for your %dth birthday.",
|
||||
config.Username,
|
||||
config.Details.Age)
|
||||
|
||||
// You can also show an usage message for your user
|
||||
Usage()
|
||||
|
||||
// Output:
|
||||
// Hello Luzifer, happy birthday for your 25th birthday.
|
||||
}
|
44
vendor/github.com/Luzifer/rconfig/float_test.go
generated
vendored
44
vendor/github.com/Luzifer/rconfig/float_test.go
generated
vendored
|
@ -1,44 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing float parsing", func() {
|
||||
type t struct {
|
||||
Test32 float32 `flag:"float32"`
|
||||
Test32P float32 `flag:"float32p,3"`
|
||||
Test64 float64 `flag:"float64"`
|
||||
Test64P float64 `flag:"float64p,6"`
|
||||
TestDef float32 `default:"66.256"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--float32=5.5", "-3", "6.6",
|
||||
"--float64=7.7", "-6", "8.8",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test32).To(Equal(float32(5.5)))
|
||||
Expect(cfg.Test32P).To(Equal(float32(6.6)))
|
||||
Expect(cfg.Test64).To(Equal(float64(7.7)))
|
||||
Expect(cfg.Test64P).To(Equal(float64(8.8)))
|
||||
|
||||
Expect(cfg.TestDef).To(Equal(float32(66.256)))
|
||||
})
|
||||
})
|
128
vendor/github.com/Luzifer/rconfig/general_test.go
generated
vendored
128
vendor/github.com/Luzifer/rconfig/general_test.go
generated
vendored
|
@ -1,128 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing general parsing", func() {
|
||||
type t struct {
|
||||
Test string `default:"foo" env:"shell" flag:"shell" description:"Test"`
|
||||
Test2 string `default:"blub" env:"testvar" flag:"testvar,t" description:"Test"`
|
||||
DefaultFlag string `default:"goo"`
|
||||
SadFlag string
|
||||
}
|
||||
|
||||
type tValidated struct {
|
||||
Test string `flag:"test" default:"" validate:"nonzero"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
Context("with defined arguments", func() {
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--shell=test23",
|
||||
"-t", "bla",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have parsed the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal("test23"))
|
||||
Expect(cfg.Test2).To(Equal("bla"))
|
||||
Expect(cfg.SadFlag).To(Equal(""))
|
||||
Expect(cfg.DefaultFlag).To(Equal("goo"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("with no arguments", func() {
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the default value", func() {
|
||||
Expect(cfg.Test).To(Equal("foo"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("with no arguments and set env", func() {
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{}
|
||||
os.Setenv("shell", "test546")
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
os.Unsetenv("shell")
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the value from env", func() {
|
||||
Expect(cfg.Test).To(Equal("test546"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("with additional arguments", func() {
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--shell=test23",
|
||||
"-t", "bla",
|
||||
"positional1", "positional2",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have parsed the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal("test23"))
|
||||
Expect(cfg.Test2).To(Equal("bla"))
|
||||
Expect(cfg.SadFlag).To(Equal(""))
|
||||
Expect(cfg.DefaultFlag).To(Equal("goo"))
|
||||
})
|
||||
It("should have detected the positional arguments", func() {
|
||||
Expect(Args()).To(Equal([]string{"positional1", "positional2"}))
|
||||
})
|
||||
})
|
||||
|
||||
Context("making use of the validator package", func() {
|
||||
var cfgValidated tValidated
|
||||
|
||||
BeforeEach(func() {
|
||||
cfgValidated = tValidated{}
|
||||
args = []string{}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parseAndValidate(&cfgValidated, args)
|
||||
})
|
||||
|
||||
It("should have errored", func() { Expect(err).To(HaveOccurred()) })
|
||||
})
|
||||
|
||||
})
|
54
vendor/github.com/Luzifer/rconfig/int_test.go
generated
vendored
54
vendor/github.com/Luzifer/rconfig/int_test.go
generated
vendored
|
@ -1,54 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing int parsing", func() {
|
||||
type t struct {
|
||||
Test int `flag:"int"`
|
||||
TestP int `flag:"intp,i"`
|
||||
Test8 int8 `flag:"int8"`
|
||||
Test8P int8 `flag:"int8p,8"`
|
||||
Test32 int32 `flag:"int32"`
|
||||
Test32P int32 `flag:"int32p,3"`
|
||||
Test64 int64 `flag:"int64"`
|
||||
Test64P int64 `flag:"int64p,6"`
|
||||
TestDef int8 `default:"66"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--int=1", "-i", "2",
|
||||
"--int8=3", "-8", "4",
|
||||
"--int32=5", "-3", "6",
|
||||
"--int64=7", "-6", "8",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal(1))
|
||||
Expect(cfg.TestP).To(Equal(2))
|
||||
Expect(cfg.Test8).To(Equal(int8(3)))
|
||||
Expect(cfg.Test8P).To(Equal(int8(4)))
|
||||
Expect(cfg.Test32).To(Equal(int32(5)))
|
||||
Expect(cfg.Test32P).To(Equal(int32(6)))
|
||||
Expect(cfg.Test64).To(Equal(int64(7)))
|
||||
Expect(cfg.Test64P).To(Equal(int64(8)))
|
||||
|
||||
Expect(cfg.TestDef).To(Equal(int8(66)))
|
||||
})
|
||||
})
|
40
vendor/github.com/Luzifer/rconfig/os-args_test.go
generated
vendored
40
vendor/github.com/Luzifer/rconfig/os-args_test.go
generated
vendored
|
@ -1,40 +0,0 @@
|
|||
package rconfig_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/Luzifer/rconfig"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing os.Args", func() {
|
||||
type t struct {
|
||||
A string `default:"a" flag:"a"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
cfg t
|
||||
)
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = Parse(&cfg)
|
||||
})
|
||||
|
||||
Context("With only valid arguments", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
os.Args = []string{"--a=bar"}
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.A).To(Equal("bar"))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
87
vendor/github.com/Luzifer/rconfig/precedence_test.go
generated
vendored
87
vendor/github.com/Luzifer/rconfig/precedence_test.go
generated
vendored
|
@ -1,87 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Precedence", func() {
|
||||
|
||||
type t struct {
|
||||
A int `default:"1" vardefault:"a" env:"a" flag:"avar,a" description:"a"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
cfg t
|
||||
args []string
|
||||
vardefaults map[string]string
|
||||
)
|
||||
|
||||
JustBeforeEach(func() {
|
||||
cfg = t{}
|
||||
SetVariableDefaults(vardefaults)
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
Context("Provided: Flag, Env, Default, VarDefault", func() {
|
||||
BeforeEach(func() {
|
||||
args = []string{"-a", "5"}
|
||||
os.Setenv("a", "8")
|
||||
vardefaults = map[string]string{
|
||||
"a": "3",
|
||||
}
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the flag value", func() {
|
||||
Expect(cfg.A).To(Equal(5))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Provided: Env, Default, VarDefault", func() {
|
||||
BeforeEach(func() {
|
||||
args = []string{}
|
||||
os.Setenv("a", "8")
|
||||
vardefaults = map[string]string{
|
||||
"a": "3",
|
||||
}
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the env value", func() {
|
||||
Expect(cfg.A).To(Equal(8))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Provided: Default, VarDefault", func() {
|
||||
BeforeEach(func() {
|
||||
args = []string{}
|
||||
os.Unsetenv("a")
|
||||
vardefaults = map[string]string{
|
||||
"a": "3",
|
||||
}
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the vardefault value", func() {
|
||||
Expect(cfg.A).To(Equal(3))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Provided: Default", func() {
|
||||
BeforeEach(func() {
|
||||
args = []string{}
|
||||
os.Unsetenv("a")
|
||||
vardefaults = map[string]string{}
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have used the default value", func() {
|
||||
Expect(cfg.A).To(Equal(1))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
13
vendor/github.com/Luzifer/rconfig/rconfig_suite_test.go
generated
vendored
13
vendor/github.com/Luzifer/rconfig/rconfig_suite_test.go
generated
vendored
|
@ -1,13 +0,0 @@
|
|||
package rconfig_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRconfig(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Rconfig Suite")
|
||||
}
|
51
vendor/github.com/Luzifer/rconfig/slice_test.go
generated
vendored
51
vendor/github.com/Luzifer/rconfig/slice_test.go
generated
vendored
|
@ -1,51 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing slices", func() {
|
||||
type t struct {
|
||||
Int []int `default:"1,2,3" flag:"int"`
|
||||
String []string `default:"a,b,c" flag:"string"`
|
||||
IntP []int `default:"1,2,3" flag:"intp,i"`
|
||||
StringP []string `default:"a,b,c" flag:"stringp,s"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--int=4,5", "-s", "hallo,welt",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values for int-slice", func() {
|
||||
Expect(len(cfg.Int)).To(Equal(2))
|
||||
Expect(cfg.Int).To(Equal([]int{4, 5}))
|
||||
Expect(cfg.Int).NotTo(Equal([]int{5, 4}))
|
||||
})
|
||||
It("should have the expected values for int-shorthand-slice", func() {
|
||||
Expect(len(cfg.IntP)).To(Equal(3))
|
||||
Expect(cfg.IntP).To(Equal([]int{1, 2, 3}))
|
||||
})
|
||||
It("should have the expected values for string-slice", func() {
|
||||
Expect(len(cfg.String)).To(Equal(3))
|
||||
Expect(cfg.String).To(Equal([]string{"a", "b", "c"}))
|
||||
})
|
||||
It("should have the expected values for string-shorthand-slice", func() {
|
||||
Expect(len(cfg.StringP)).To(Equal(2))
|
||||
Expect(cfg.StringP).To(Equal([]string{"hallo", "welt"}))
|
||||
})
|
||||
})
|
36
vendor/github.com/Luzifer/rconfig/sub-struct_test.go
generated
vendored
36
vendor/github.com/Luzifer/rconfig/sub-struct_test.go
generated
vendored
|
@ -1,36 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing sub-structs", func() {
|
||||
type t struct {
|
||||
Test string `default:"blubb"`
|
||||
Sub struct {
|
||||
Test string `default:"Hallo"`
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal("blubb"))
|
||||
Expect(cfg.Sub.Test).To(Equal("Hallo"))
|
||||
})
|
||||
})
|
59
vendor/github.com/Luzifer/rconfig/uint_test.go
generated
vendored
59
vendor/github.com/Luzifer/rconfig/uint_test.go
generated
vendored
|
@ -1,59 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing uint parsing", func() {
|
||||
type t struct {
|
||||
Test uint `flag:"int"`
|
||||
TestP uint `flag:"intp,i"`
|
||||
Test8 uint8 `flag:"int8"`
|
||||
Test8P uint8 `flag:"int8p,8"`
|
||||
Test16 uint16 `flag:"int16"`
|
||||
Test16P uint16 `flag:"int16p,1"`
|
||||
Test32 uint32 `flag:"int32"`
|
||||
Test32P uint32 `flag:"int32p,3"`
|
||||
Test64 uint64 `flag:"int64"`
|
||||
Test64P uint64 `flag:"int64p,6"`
|
||||
TestDef uint8 `default:"66"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
args []string
|
||||
cfg t
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
args = []string{
|
||||
"--int=1", "-i", "2",
|
||||
"--int8=3", "-8", "4",
|
||||
"--int32=5", "-3", "6",
|
||||
"--int64=7", "-6", "8",
|
||||
"--int16=9", "-1", "10",
|
||||
}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.Test).To(Equal(uint(1)))
|
||||
Expect(cfg.TestP).To(Equal(uint(2)))
|
||||
Expect(cfg.Test8).To(Equal(uint8(3)))
|
||||
Expect(cfg.Test8P).To(Equal(uint8(4)))
|
||||
Expect(cfg.Test32).To(Equal(uint32(5)))
|
||||
Expect(cfg.Test32P).To(Equal(uint32(6)))
|
||||
Expect(cfg.Test64).To(Equal(uint64(7)))
|
||||
Expect(cfg.Test64P).To(Equal(uint64(8)))
|
||||
Expect(cfg.Test16).To(Equal(uint16(9)))
|
||||
Expect(cfg.Test16P).To(Equal(uint16(10)))
|
||||
|
||||
Expect(cfg.TestDef).To(Equal(uint8(66)))
|
||||
})
|
||||
})
|
122
vendor/github.com/Luzifer/rconfig/vardefault_test.go
generated
vendored
122
vendor/github.com/Luzifer/rconfig/vardefault_test.go
generated
vendored
|
@ -1,122 +0,0 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Testing variable defaults", func() {
|
||||
|
||||
type t struct {
|
||||
MySecretValue string `default:"secret" env:"foo" vardefault:"my_secret_value"`
|
||||
MyUsername string `default:"luzifer" vardefault:"username"`
|
||||
SomeVar string `flag:"var" description:"some variable"`
|
||||
IntVar int64 `vardefault:"int_var" default:"23"`
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
cfg t
|
||||
args = []string{}
|
||||
vardefaults = map[string]string{
|
||||
"my_secret_value": "veryverysecretkey",
|
||||
"unkownkey": "hi there",
|
||||
"int_var": "42",
|
||||
}
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cfg = t{}
|
||||
})
|
||||
|
||||
JustBeforeEach(func() {
|
||||
err = parse(&cfg, args)
|
||||
})
|
||||
|
||||
Context("With manually provided variables", func() {
|
||||
BeforeEach(func() {
|
||||
SetVariableDefaults(vardefaults)
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.IntVar).To(Equal(int64(42)))
|
||||
Expect(cfg.MySecretValue).To(Equal("veryverysecretkey"))
|
||||
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||
Expect(cfg.SomeVar).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
Context("With defaults from YAML data", func() {
|
||||
BeforeEach(func() {
|
||||
yamlData := []byte("---\nmy_secret_value: veryverysecretkey\nunknownkey: hi there\nint_var: 42\n")
|
||||
SetVariableDefaults(VarDefaultsFromYAML(yamlData))
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.IntVar).To(Equal(int64(42)))
|
||||
Expect(cfg.MySecretValue).To(Equal("veryverysecretkey"))
|
||||
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||
Expect(cfg.SomeVar).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
Context("With defaults from YAML file", func() {
|
||||
var tmp *os.File
|
||||
|
||||
BeforeEach(func() {
|
||||
tmp, _ = ioutil.TempFile("", "")
|
||||
yamlData := "---\nmy_secret_value: veryverysecretkey\nunknownkey: hi there\nint_var: 42\n"
|
||||
tmp.WriteString(yamlData)
|
||||
SetVariableDefaults(VarDefaultsFromYAMLFile(tmp.Name()))
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
tmp.Close()
|
||||
os.Remove(tmp.Name())
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.IntVar).To(Equal(int64(42)))
|
||||
Expect(cfg.MySecretValue).To(Equal("veryverysecretkey"))
|
||||
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||
Expect(cfg.SomeVar).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
Context("With defaults from invalid YAML data", func() {
|
||||
BeforeEach(func() {
|
||||
yamlData := []byte("---\nmy_secret_value = veryverysecretkey\nunknownkey = hi there\nint_var = 42\n")
|
||||
SetVariableDefaults(VarDefaultsFromYAML(yamlData))
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.IntVar).To(Equal(int64(23)))
|
||||
Expect(cfg.MySecretValue).To(Equal("secret"))
|
||||
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||
Expect(cfg.SomeVar).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
Context("With defaults from non existent YAML file", func() {
|
||||
BeforeEach(func() {
|
||||
file := "/tmp/this_file_should_not_exist_146e26723r"
|
||||
SetVariableDefaults(VarDefaultsFromYAMLFile(file))
|
||||
})
|
||||
|
||||
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||
It("should have the expected values", func() {
|
||||
Expect(cfg.IntVar).To(Equal(int64(23)))
|
||||
Expect(cfg.MySecretValue).To(Equal("secret"))
|
||||
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||
Expect(cfg.SomeVar).To(Equal(""))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
14
vendor/github.com/aws/aws-sdk-go/.github/ISSUE_TEMPLATE.md
generated
vendored
14
vendor/github.com/aws/aws-sdk-go/.github/ISSUE_TEMPLATE.md
generated
vendored
|
@ -1,14 +0,0 @@
|
|||
Please fill out the sections below to help us address your issue.
|
||||
|
||||
### Version of AWS SDK for Go?
|
||||
|
||||
|
||||
### Version of Go (`go version`)?
|
||||
|
||||
|
||||
### What issue did you see?
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
If you have have an runnable example, please include it.
|
||||
|
3
vendor/github.com/aws/aws-sdk-go/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
3
vendor/github.com/aws/aws-sdk-go/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
|
@ -1,3 +0,0 @@
|
|||
For changes to files under the `/model/` folder, and manual edits to autogenerated code (e.g. `/service/s3/api.go`) please create an Issue instead of a PR for those type of changes.
|
||||
|
||||
If there is an existing bug or feature this PR is answers please reference it here.
|
11
vendor/github.com/aws/aws-sdk-go/.gitignore
generated
vendored
11
vendor/github.com/aws/aws-sdk-go/.gitignore
generated
vendored
|
@ -1,11 +0,0 @@
|
|||
dist
|
||||
/doc
|
||||
/doc-staging
|
||||
.yardoc
|
||||
Gemfile.lock
|
||||
awstesting/integration/smoke/**/importmarker__.go
|
||||
awstesting/integration/smoke/_test/
|
||||
/vendor/bin/
|
||||
/vendor/pkg/
|
||||
/vendor/src/
|
||||
/private/model/cli/gen-api/gen-api
|
14
vendor/github.com/aws/aws-sdk-go/.godoc_config
generated
vendored
14
vendor/github.com/aws/aws-sdk-go/.godoc_config
generated
vendored
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"PkgHandler": {
|
||||
"Pattern": "/sdk-for-go/api/",
|
||||
"StripPrefix": "/sdk-for-go/api",
|
||||
"Include": ["/src/github.com/aws/aws-sdk-go/aws", "/src/github.com/aws/aws-sdk-go/service"],
|
||||
"Exclude": ["/src/cmd", "/src/github.com/aws/aws-sdk-go/awstesting", "/src/github.com/aws/aws-sdk-go/awsmigrate"],
|
||||
"IgnoredSuffixes": ["iface"]
|
||||
},
|
||||
"Github": {
|
||||
"Tag": "master",
|
||||
"Repo": "/aws/aws-sdk-go",
|
||||
"UseGithub": true
|
||||
}
|
||||
}
|
29
vendor/github.com/aws/aws-sdk-go/.travis.yml
generated
vendored
29
vendor/github.com/aws/aws-sdk-go/.travis.yml
generated
vendored
|
@ -1,29 +0,0 @@
|
|||
language: go
|
||||
|
||||
sudo: required
|
||||
|
||||
go:
|
||||
- 1.5.x
|
||||
- 1.6.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- tip
|
||||
|
||||
# Use Go 1.5's vendoring experiment for 1.5 tests.
|
||||
env:
|
||||
- GO15VENDOREXPERIMENT=1
|
||||
|
||||
install:
|
||||
- make get-deps
|
||||
|
||||
script:
|
||||
- make unit-with-race-cover
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
2296
vendor/github.com/aws/aws-sdk-go/CHANGELOG.md
generated
vendored
2296
vendor/github.com/aws/aws-sdk-go/CHANGELOG.md
generated
vendored
File diff suppressed because it is too large
Load diff
5
vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md
generated
vendored
5
vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md
generated
vendored
|
@ -1,5 +0,0 @@
|
|||
### SDK Features
|
||||
|
||||
### SDK Enhancements
|
||||
|
||||
### SDK Bugs
|
127
vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md
generated
vendored
127
vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md
generated
vendored
|
@ -1,127 +0,0 @@
|
|||
Contributing to the AWS SDK for Go
|
||||
|
||||
We work hard to provide a high-quality and useful SDK, and we greatly value
|
||||
feedback and contributions from our community. Whether it's a bug report,
|
||||
new feature, correction, or additional documentation, we welcome your issues
|
||||
and pull requests. Please read through this document before submitting any
|
||||
issues or pull requests to ensure we have all the necessary information to
|
||||
effectively respond to your bug report or contribution.
|
||||
|
||||
|
||||
## Filing Bug Reports
|
||||
|
||||
You can file bug reports against the SDK on the [GitHub issues][issues] page.
|
||||
|
||||
If you are filing a report for a bug or regression in the SDK, it's extremely
|
||||
helpful to provide as much information as possible when opening the original
|
||||
issue. This helps us reproduce and investigate the possible bug without having
|
||||
to wait for this extra information to be provided. Please read the following
|
||||
guidelines prior to filing a bug report.
|
||||
|
||||
1. Search through existing [issues][] to ensure that your specific issue has
|
||||
not yet been reported. If it is a common issue, it is likely there is
|
||||
already a bug report for your problem.
|
||||
|
||||
2. Ensure that you have tested the latest version of the SDK. Although you
|
||||
may have an issue against an older version of the SDK, we cannot provide
|
||||
bug fixes for old versions. It's also possible that the bug may have been
|
||||
fixed in the latest release.
|
||||
|
||||
3. Provide as much information about your environment, SDK version, and
|
||||
relevant dependencies as possible. For example, let us know what version
|
||||
of Go you are using, which and version of the operating system, and the
|
||||
the environment your code is running in. e.g Container.
|
||||
|
||||
4. Provide a minimal test case that reproduces your issue or any error
|
||||
information you related to your problem. We can provide feedback much
|
||||
more quickly if we know what operations you are calling in the SDK. If
|
||||
you cannot provide a full test case, provide as much code as you can
|
||||
to help us diagnose the problem. Any relevant information should be provided
|
||||
as well, like whether this is a persistent issue, or if it only occurs
|
||||
some of the time.
|
||||
|
||||
|
||||
## Submitting Pull Requests
|
||||
|
||||
We are always happy to receive code and documentation contributions to the SDK.
|
||||
Please be aware of the following notes prior to opening a pull request:
|
||||
|
||||
1. The SDK is released under the [Apache license][license]. Any code you submit
|
||||
will be released under that license. For substantial contributions, we may
|
||||
ask you to sign a [Contributor License Agreement (CLA)][cla].
|
||||
|
||||
2. If you would like to implement support for a significant feature that is not
|
||||
yet available in the SDK, please talk to us beforehand to avoid any
|
||||
duplication of effort.
|
||||
|
||||
3. Wherever possible, pull requests should contain tests as appropriate.
|
||||
Bugfixes should contain tests that exercise the corrected behavior (i.e., the
|
||||
test should fail without the bugfix and pass with it), and new features
|
||||
should be accompanied by tests exercising the feature.
|
||||
|
||||
4. Pull requests that contain failing tests will not be merged until the test
|
||||
failures are addressed. Pull requests that cause a significant drop in the
|
||||
SDK's test coverage percentage are unlikely to be merged until tests have
|
||||
been added.
|
||||
|
||||
5. The JSON files under the SDK's `models` folder are sourced from outside the SDK.
|
||||
Such as `models/apis/ec2/2016-11-15/api.json`. We will not accept pull requests
|
||||
directly on these models. If you discover an issue with the models please
|
||||
create a [GitHub issue][issues] describing the issue.
|
||||
|
||||
### Testing
|
||||
|
||||
To run the tests locally, running the `make unit` command will `go get` the
|
||||
SDK's testing dependencies, and run vet, link and unit tests for the SDK.
|
||||
|
||||
```
|
||||
make unit
|
||||
```
|
||||
|
||||
Standard go testing functionality is supported as well. To test SDK code that
|
||||
is tagged with `codegen` you'll need to set the build tag in the go test
|
||||
command. The `make unit` command will do this automatically.
|
||||
|
||||
```
|
||||
go test -tags codegen ./private/...
|
||||
```
|
||||
|
||||
See the `Makefile` for additional testing tags that can be used in testing.
|
||||
|
||||
To test on multiple platform the SDK includes several DockerFiles under the
|
||||
`awstesting/sandbox` folder, and associated make recipes to to execute
|
||||
unit testing within environments configured for specific Go versions.
|
||||
|
||||
```
|
||||
make sandbox-test-go18
|
||||
```
|
||||
|
||||
To run all sandbox environments use the following make recipe
|
||||
|
||||
```
|
||||
# Optionally update the Go tip that will be used during the batch testing
|
||||
make update-aws-golang-tip
|
||||
|
||||
# Run all SDK tests for supported Go versions in sandboxes
|
||||
make sandbox-test
|
||||
```
|
||||
|
||||
In addition the sandbox environment include make recipes for interactive modes
|
||||
so you can run command within the Docker container and context of the SDK.
|
||||
|
||||
```
|
||||
make sandbox-go18
|
||||
```
|
||||
|
||||
### Changelog
|
||||
|
||||
You can see all release changes in the `CHANGELOG.md` file at the root of the
|
||||
repository. The release notes added to this file will contain service client
|
||||
updates, and major SDK changes.
|
||||
|
||||
[issues]: https://github.com/aws/aws-sdk-go/issues
|
||||
[pr]: https://github.com/aws/aws-sdk-go/pulls
|
||||
[license]: http://aws.amazon.com/apache2.0/
|
||||
[cla]: http://en.wikipedia.org/wiki/Contributor_License_Agreement
|
||||
[releasenotes]: https://github.com/aws/aws-sdk-go/releases
|
||||
|
20
vendor/github.com/aws/aws-sdk-go/Gopkg.lock
generated
vendored
20
vendor/github.com/aws/aws-sdk-go/Gopkg.lock
generated
vendored
|
@ -1,20 +0,0 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-ini/ini"
|
||||
packages = ["."]
|
||||
revision = "300e940a926eb277d3901b20bdfcc54928ad3642"
|
||||
version = "v1.25.4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
packages = ["."]
|
||||
revision = "0b12d6b5"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "51a86a867df617990082dec6b868e4efe2fdb2ed0e02a3daa93cd30f962b5085"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
48
vendor/github.com/aws/aws-sdk-go/Gopkg.toml
generated
vendored
48
vendor/github.com/aws/aws-sdk-go/Gopkg.toml
generated
vendored
|
@ -1,48 +0,0 @@
|
|||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
ignored = [
|
||||
# Testing/Example/Codegen dependencies
|
||||
"github.com/stretchr/testify",
|
||||
"github.com/stretchr/testify/assert",
|
||||
"github.com/stretchr/testify/require",
|
||||
"github.com/go-sql-driver/mysql",
|
||||
"github.com/gucumber/gucumber",
|
||||
"github.com/pkg/errors",
|
||||
"golang.org/x/net",
|
||||
"golang.org/x/net/html",
|
||||
"golang.org/x/net/http2",
|
||||
"golang.org/x/text",
|
||||
"golang.org/x/text/html",
|
||||
"golang.org/x/tools",
|
||||
"golang.org/x/tools/go/loader",
|
||||
]
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-ini/ini"
|
||||
version = "1.25.4"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
revision = "0b12d6b5"
|
||||
#version = "0.2.2"
|
187
vendor/github.com/aws/aws-sdk-go/Makefile
generated
vendored
187
vendor/github.com/aws/aws-sdk-go/Makefile
generated
vendored
|
@ -1,187 +0,0 @@
|
|||
LINTIGNOREDOT='awstesting/integration.+should not use dot imports'
|
||||
LINTIGNOREDOC='service/[^/]+/(api|service|waiters)\.go:.+(comment on exported|should have comment or be unexported)'
|
||||
LINTIGNORECONST='service/[^/]+/(api|service|waiters)\.go:.+(type|struct field|const|func) ([^ ]+) should be ([^ ]+)'
|
||||
LINTIGNORESTUTTER='service/[^/]+/(api|service)\.go:.+(and that stutters)'
|
||||
LINTIGNOREINFLECT='service/[^/]+/(api|errors|service)\.go:.+(method|const) .+ should be '
|
||||
LINTIGNOREINFLECTS3UPLOAD='service/s3/s3manager/upload\.go:.+struct field SSEKMSKeyId should be '
|
||||
LINTIGNOREDEPS='vendor/.+\.go'
|
||||
LINTIGNOREPKGCOMMENT='service/[^/]+/doc_custom.go:.+package comment should be of the form'
|
||||
UNIT_TEST_TAGS="example codegen awsinclude"
|
||||
|
||||
SDK_WITH_VENDOR_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/src")
|
||||
SDK_ONLY_PKGS=$(shell go list ./... | grep -v "/vendor/")
|
||||
SDK_UNIT_TEST_ONLY_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/")
|
||||
SDK_GO_1_4=$(shell go version | grep "go1.4")
|
||||
SDK_GO_1_5=$(shell go version | grep "go1.5")
|
||||
SDK_GO_VERSION=$(shell go version | awk '''{print $$3}''' | tr -d '''\n''')
|
||||
|
||||
all: get-deps generate unit
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " api_info to print a list of services and versions"
|
||||
@echo " docs to build SDK documentation"
|
||||
@echo " build to go build the SDK"
|
||||
@echo " unit to run unit tests"
|
||||
@echo " integration to run integration tests"
|
||||
@echo " performance to run performance tests"
|
||||
@echo " verify to verify tests"
|
||||
@echo " lint to lint the SDK"
|
||||
@echo " vet to vet the SDK"
|
||||
@echo " generate to go generate and make services"
|
||||
@echo " gen-test to generate protocol tests"
|
||||
@echo " gen-services to generate services"
|
||||
@echo " get-deps to go get the SDK dependencies"
|
||||
@echo " get-deps-tests to get the SDK's test dependencies"
|
||||
@echo " get-deps-verify to get the SDK's verification dependencies"
|
||||
|
||||
generate: gen-test gen-endpoints gen-services
|
||||
|
||||
gen-test: gen-protocol-test
|
||||
|
||||
gen-services:
|
||||
go generate ./service
|
||||
|
||||
gen-protocol-test:
|
||||
go generate ./private/protocol/...
|
||||
|
||||
gen-endpoints:
|
||||
go generate ./models/endpoints/
|
||||
|
||||
build:
|
||||
@echo "go build SDK and vendor packages"
|
||||
@go build ${SDK_ONLY_PKGS}
|
||||
|
||||
unit: get-deps-tests build verify
|
||||
@echo "go test SDK and vendor packages"
|
||||
@go test -tags ${UNIT_TEST_TAGS} $(SDK_UNIT_TEST_ONLY_PKGS)
|
||||
|
||||
unit-with-race-cover: get-deps-tests build verify
|
||||
@echo "go test SDK and vendor packages"
|
||||
@go test -tags ${UNIT_TEST_TAGS} -race -cpu=1,2,4 $(SDK_UNIT_TEST_ONLY_PKGS)
|
||||
|
||||
integration: get-deps-tests integ-custom smoke-tests performance
|
||||
|
||||
integ-custom:
|
||||
go test -tags "integration" ./awstesting/integration/customizations/...
|
||||
|
||||
cleanup-integ:
|
||||
go run -tags "integration" ./awstesting/cmd/bucket_cleanup/main.go "aws-sdk-go-integration"
|
||||
|
||||
smoke-tests: get-deps-tests
|
||||
gucumber -go-tags "integration" ./awstesting/integration/smoke
|
||||
|
||||
performance: get-deps-tests
|
||||
AWS_TESTING_LOG_RESULTS=${log-detailed} AWS_TESTING_REGION=$(region) AWS_TESTING_DB_TABLE=$(table) gucumber -go-tags "integration" ./awstesting/performance
|
||||
|
||||
sandbox-tests: sandbox-test-go15 sandbox-test-go15-novendorexp sandbox-test-go16 sandbox-test-go17 sandbox-test-go18 sandbox-test-go19 sandbox-test-gotip
|
||||
|
||||
sandbox-build-go15:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5 -t "aws-sdk-go-1.5" .
|
||||
sandbox-go15: sandbox-build-go15
|
||||
docker run -i -t aws-sdk-go-1.5 bash
|
||||
sandbox-test-go15: sandbox-build-go15
|
||||
docker run -t aws-sdk-go-1.5
|
||||
|
||||
sandbox-build-go15-novendorexp:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5-novendorexp -t "aws-sdk-go-1.5-novendorexp" .
|
||||
sandbox-go15-novendorexp: sandbox-build-go15-novendorexp
|
||||
docker run -i -t aws-sdk-go-1.5-novendorexp bash
|
||||
sandbox-test-go15-novendorexp: sandbox-build-go15-novendorexp
|
||||
docker run -t aws-sdk-go-1.5-novendorexp
|
||||
|
||||
sandbox-build-go16:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.6 -t "aws-sdk-go-1.6" .
|
||||
sandbox-go16: sandbox-build-go16
|
||||
docker run -i -t aws-sdk-go-1.6 bash
|
||||
sandbox-test-go16: sandbox-build-go16
|
||||
docker run -t aws-sdk-go-1.6
|
||||
|
||||
sandbox-build-go17:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.7 -t "aws-sdk-go-1.7" .
|
||||
sandbox-go17: sandbox-build-go17
|
||||
docker run -i -t aws-sdk-go-1.7 bash
|
||||
sandbox-test-go17: sandbox-build-go17
|
||||
docker run -t aws-sdk-go-1.7
|
||||
|
||||
sandbox-build-go18:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.8" .
|
||||
sandbox-go18: sandbox-build-go18
|
||||
docker run -i -t aws-sdk-go-1.8 bash
|
||||
sandbox-test-go18: sandbox-build-go18
|
||||
docker run -t aws-sdk-go-1.8
|
||||
|
||||
sandbox-build-go19:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.9" .
|
||||
sandbox-go19: sandbox-build-go19
|
||||
docker run -i -t aws-sdk-go-1.9 bash
|
||||
sandbox-test-go19: sandbox-build-go19
|
||||
docker run -t aws-sdk-go-1.9
|
||||
|
||||
sandbox-build-gotip:
|
||||
@echo "Run make update-aws-golang-tip, if this test fails because missing aws-golang:tip container"
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.gotip -t "aws-sdk-go-tip" .
|
||||
sandbox-gotip: sandbox-build-gotip
|
||||
docker run -i -t aws-sdk-go-tip bash
|
||||
sandbox-test-gotip: sandbox-build-gotip
|
||||
docker run -t aws-sdk-go-tip
|
||||
|
||||
update-aws-golang-tip:
|
||||
docker build --no-cache=true -f ./awstesting/sandbox/Dockerfile.golang-tip -t "aws-golang:tip" .
|
||||
|
||||
verify: get-deps-verify lint vet
|
||||
|
||||
lint:
|
||||
@echo "go lint SDK and vendor packages"
|
||||
@lint=`if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then golint ./...; else echo "skipping golint"; fi`; \
|
||||
lint=`echo "$$lint" | grep -E -v -e ${LINTIGNOREDOT} -e ${LINTIGNOREDOC} -e ${LINTIGNORECONST} -e ${LINTIGNORESTUTTER} -e ${LINTIGNOREINFLECT} -e ${LINTIGNOREDEPS} -e ${LINTIGNOREINFLECTS3UPLOAD} -e ${LINTIGNOREPKGCOMMENT}`; \
|
||||
echo "$$lint"; \
|
||||
if [ "$$lint" != "" ] && [ "$$lint" != "skipping golint" ]; then exit 1; fi
|
||||
|
||||
SDK_BASE_FOLDERS=$(shell ls -d */ | grep -v vendor | grep -v awsmigrate)
|
||||
ifneq (,$(findstring go1.4, ${SDK_GO_VERSION}))
|
||||
GO_VET_CMD=echo skipping go vet, ${SDK_GO_VERSION}
|
||||
else ifneq (,$(findstring go1.6, ${SDK_GO_VERSION}))
|
||||
GO_VET_CMD=go tool vet --all -shadow -example=false
|
||||
else
|
||||
GO_VET_CMD=go tool vet --all -shadow
|
||||
endif
|
||||
|
||||
vet:
|
||||
${GO_VET_CMD} ${SDK_BASE_FOLDERS}
|
||||
|
||||
get-deps: get-deps-tests get-deps-verify
|
||||
@echo "go get SDK dependencies"
|
||||
@go get -v $(SDK_ONLY_PKGS)
|
||||
|
||||
get-deps-tests:
|
||||
@echo "go get SDK testing dependencies"
|
||||
go get github.com/gucumber/gucumber/cmd/gucumber
|
||||
go get github.com/stretchr/testify
|
||||
go get github.com/smartystreets/goconvey
|
||||
go get golang.org/x/net/html
|
||||
go get golang.org/x/net/http2
|
||||
|
||||
get-deps-verify:
|
||||
@echo "go get SDK verification utilities"
|
||||
@if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then go get github.com/golang/lint/golint; else echo "skipped getting golint"; fi
|
||||
|
||||
bench:
|
||||
@echo "go bench SDK packages"
|
||||
@go test -run NONE -bench . -benchmem -tags 'bench' $(SDK_ONLY_PKGS)
|
||||
|
||||
bench-protocol:
|
||||
@echo "go bench SDK protocol marshallers"
|
||||
@go test -run NONE -bench . -benchmem -tags 'bench' ./private/protocol/...
|
||||
|
||||
docs:
|
||||
@echo "generate SDK docs"
|
||||
@# This env variable, DOCS, is for internal use
|
||||
@if [ -z ${AWS_DOC_GEN_TOOL} ]; then\
|
||||
rm -rf doc && bundle install && bundle exec yard;\
|
||||
else\
|
||||
$(AWS_DOC_GEN_TOOL) `pwd`;\
|
||||
fi
|
||||
|
||||
api_info:
|
||||
@go run private/model/cli/api-info/api-info.go
|
449
vendor/github.com/aws/aws-sdk-go/README.md
generated
vendored
449
vendor/github.com/aws/aws-sdk-go/README.md
generated
vendored
|
@ -1,449 +0,0 @@
|
|||
[![API Reference](http://img.shields.io/badge/api-reference-blue.svg)](http://docs.aws.amazon.com/sdk-for-go/api) [![Join the chat at https://gitter.im/aws/aws-sdk-go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://img.shields.io/travis/aws/aws-sdk-go.svg)](https://travis-ci.org/aws/aws-sdk-go) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
|
||||
|
||||
# AWS SDK for Go
|
||||
|
||||
aws-sdk-go is the official AWS SDK for the Go programming language.
|
||||
|
||||
Checkout our [release notes](https://github.com/aws/aws-sdk-go/releases) for information about the latest bug fixes, updates, and features added to the SDK.
|
||||
|
||||
## Installing
|
||||
|
||||
If you are using Go 1.5 with the `GO15VENDOREXPERIMENT=1` vendoring flag, or 1.6 and higher you can use the following command to retrieve the SDK. The SDK's non-testing dependencies will be included and are vendored in the `vendor` folder.
|
||||
|
||||
go get -u github.com/aws/aws-sdk-go
|
||||
|
||||
Otherwise if your Go environment does not have vendoring support enabled, or you do not want to include the vendored SDK's dependencies you can use the following command to retrieve the SDK and its non-testing dependencies using `go get`.
|
||||
|
||||
go get -u github.com/aws/aws-sdk-go/aws/...
|
||||
go get -u github.com/aws/aws-sdk-go/service/...
|
||||
|
||||
If you're looking to retrieve just the SDK without any dependencies use the following command.
|
||||
|
||||
go get -d github.com/aws/aws-sdk-go/
|
||||
|
||||
These two processes will still include the `vendor` folder and it should be deleted if its not going to be used by your environment.
|
||||
|
||||
rm -rf $GOPATH/src/github.com/aws/aws-sdk-go/vendor
|
||||
|
||||
## Getting Help
|
||||
|
||||
Please use these community resources for getting help. We use the GitHub issues for tracking bugs and feature requests.
|
||||
|
||||
* Ask a question on [StackOverflow](http://stackoverflow.com/) and tag it with the [`aws-sdk-go`](http://stackoverflow.com/questions/tagged/aws-sdk-go) tag.
|
||||
* Come join the AWS SDK for Go community chat on [gitter](https://gitter.im/aws/aws-sdk-go).
|
||||
* Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html).
|
||||
* If you think you may have found a bug, please open an [issue](https://github.com/aws/aws-sdk-go/issues/new).
|
||||
|
||||
## Opening Issues
|
||||
|
||||
If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the [existing issues](https://github.com/aws/aws-sdk-go/issues) and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS you’re using. Please also include repro case when appropriate.
|
||||
|
||||
The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help](https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner.
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
[`Getting Started Guide`](https://aws.amazon.com/sdk-for-go/) - This document is a general introduction how to configure and make requests with the SDK. If this is your first time using the SDK, this documentation and the API documentation will help you get started. This document focuses on the syntax and behavior of the SDK. The [Service Developer Guide](https://aws.amazon.com/documentation/) will help you get started using specific AWS services.
|
||||
|
||||
[`SDK API Reference Documentation`](https://docs.aws.amazon.com/sdk-for-go/api/) - Use this document to look up all API operation input and output parameters for AWS services supported by the SDK. The API reference also includes documentation of the SDK, and examples how to using the SDK, service client API operations, and API operation require parameters.
|
||||
|
||||
[`Service Developer Guide`](https://aws.amazon.com/documentation/) - Use this documentation to learn how to interface with an AWS service. These are great guides both, if you're getting started with a service, or looking for more information on a service. You should not need this document for coding, though in some cases, services may supply helpful samples that you might want to look out for.
|
||||
|
||||
[`SDK Examples`](https://github.com/aws/aws-sdk-go/tree/master/example) - Included in the SDK's repo are a several hand crafted examples using the SDK features and AWS services.
|
||||
|
||||
## Overview of SDK's Packages
|
||||
|
||||
The SDK is composed of two main components, SDK core, and service clients.
|
||||
The SDK core packages are all available under the aws package at the root of
|
||||
the SDK. Each client for a supported AWS service is available within its own
|
||||
package under the service folder at the root of the SDK.
|
||||
|
||||
* aws - SDK core, provides common shared types such as Config, Logger,
|
||||
and utilities to make working with API parameters easier.
|
||||
|
||||
* awserr - Provides the error interface that the SDK will use for all
|
||||
errors that occur in the SDK's processing. This includes service API
|
||||
response errors as well. The Error type is made up of a code and message.
|
||||
Cast the SDK's returned error type to awserr.Error and call the Code
|
||||
method to compare returned error to specific error codes. See the package's
|
||||
documentation for additional values that can be extracted such as RequestID.
|
||||
|
||||
* credentials - Provides the types and built in credentials providers
|
||||
the SDK will use to retrieve AWS credentials to make API requests with.
|
||||
Nested under this folder are also additional credentials providers such as
|
||||
stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles.
|
||||
|
||||
* endpoints - Provides the AWS Regions and Endpoints metadata for the SDK.
|
||||
Use this to lookup AWS service endpoint information such as which services
|
||||
are in a region, and what regions a service is in. Constants are also provided
|
||||
for all region identifiers, e.g UsWest2RegionID for "us-west-2".
|
||||
|
||||
* session - Provides initial default configuration, and load
|
||||
configuration from external sources such as environment and shared
|
||||
credentials file.
|
||||
|
||||
* request - Provides the API request sending, and retry logic for the SDK.
|
||||
This package also includes utilities for defining your own request
|
||||
retryer, and configuring how the SDK processes the request.
|
||||
|
||||
* service - Clients for AWS services. All services supported by the SDK are
|
||||
available under this folder.
|
||||
|
||||
## How to Use the SDK's AWS Service Clients
|
||||
|
||||
The SDK includes the Go types and utilities you can use to make requests to
|
||||
AWS service APIs. Within the service folder at the root of the SDK you'll find
|
||||
a package for each AWS service the SDK supports. All service clients follows
|
||||
a common pattern of creation and usage.
|
||||
|
||||
When creating a client for an AWS service you'll first need to have a Session
|
||||
value constructed. The Session provides shared configuration that can be shared
|
||||
between your service clients. When service clients are created you can pass
|
||||
in additional configuration via the aws.Config type to override configuration
|
||||
provided by in the Session to create service client instances with custom
|
||||
configuration.
|
||||
|
||||
Once the service's client is created you can use it to make API requests the
|
||||
AWS service. These clients are safe to use concurrently.
|
||||
|
||||
## Configuring the SDK
|
||||
|
||||
In the AWS SDK for Go, you can configure settings for service clients, such
|
||||
as the log level and maximum number of retries. Most settings are optional;
|
||||
however, for each service client, you must specify a region and your credentials.
|
||||
The SDK uses these values to send requests to the correct AWS region and sign
|
||||
requests with the correct credentials. You can specify these values as part
|
||||
of a session or as environment variables.
|
||||
|
||||
See the SDK's [configuration guide][config_guide] for more information.
|
||||
|
||||
See the [session][session_pkg] package documentation for more information on how to use Session
|
||||
with the SDK.
|
||||
|
||||
See the [Config][config_typ] type in the [aws][aws_pkg] package for more information on configuration
|
||||
options.
|
||||
|
||||
[config_guide]: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html
|
||||
[session_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/session/
|
||||
[config_typ]: https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
|
||||
[aws_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/
|
||||
|
||||
### Configuring Credentials
|
||||
|
||||
When using the SDK you'll generally need your AWS credentials to authenticate
|
||||
with AWS services. The SDK supports multiple methods of supporting these
|
||||
credentials. By default the SDK will source credentials automatically from
|
||||
its default credential chain. See the session package for more information
|
||||
on this chain, and how to configure it. The common items in the credential
|
||||
chain are the following:
|
||||
|
||||
* Environment Credentials - Set of environment variables that are useful
|
||||
when sub processes are created for specific roles.
|
||||
|
||||
* Shared Credentials file (~/.aws/credentials) - This file stores your
|
||||
credentials based on a profile name and is useful for local development.
|
||||
|
||||
* EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials
|
||||
to application running on an EC2 instance. This removes the need to manage
|
||||
credential files in production.
|
||||
|
||||
Credentials can be configured in code as well by setting the Config's Credentials
|
||||
value to a custom provider or using one of the providers included with the
|
||||
SDK to bypass the default credential chain and use a custom one. This is
|
||||
helpful when you want to instruct the SDK to only use a specific set of
|
||||
credentials or providers.
|
||||
|
||||
This example creates a credential provider for assuming an IAM role, "myRoleARN"
|
||||
and configures the S3 service client to use that role for API requests.
|
||||
|
||||
```go
|
||||
// Initial credentials loaded from SDK's default credential chain. Such as
|
||||
// the environment, shared credentials (~/.aws/credentials), or EC2 Instance
|
||||
// Role. These credentials will be used to to make the STS Assume Role API.
|
||||
sess := session.Must(session.NewSession())
|
||||
|
||||
// Create the credentials from AssumeRoleProvider to assume the role
|
||||
// referenced by the "myRoleARN" ARN.
|
||||
creds := stscreds.NewCredentials(sess, "myRoleArn")
|
||||
|
||||
// Create service client value configured for credentials
|
||||
// from assumed role.
|
||||
svc := s3.New(sess, &aws.Config{Credentials: creds})
|
||||
```
|
||||
|
||||
See the [credentials][credentials_pkg] package documentation for more information on credential
|
||||
providers included with the SDK, and how to customize the SDK's usage of
|
||||
credentials.
|
||||
|
||||
The SDK has support for the shared configuration file (~/.aws/config). This
|
||||
support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1",
|
||||
or enabling the feature in code when creating a Session via the
|
||||
Option's SharedConfigState parameter.
|
||||
|
||||
```go
|
||||
sess := session.Must(session.NewSessionWithOptions(session.Options{
|
||||
SharedConfigState: session.SharedConfigEnable,
|
||||
}))
|
||||
```
|
||||
|
||||
[credentials_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials
|
||||
|
||||
### Configuring AWS Region
|
||||
|
||||
In addition to the credentials you'll need to specify the region the SDK
|
||||
will use to make AWS API requests to. In the SDK you can specify the region
|
||||
either with an environment variable, or directly in code when a Session or
|
||||
service client is created. The last value specified in code wins if the region
|
||||
is specified multiple ways.
|
||||
|
||||
To set the region via the environment variable set the "AWS_REGION" to the
|
||||
region you want to the SDK to use. Using this method to set the region will
|
||||
allow you to run your application in multiple regions without needing additional
|
||||
code in the application to select the region.
|
||||
|
||||
AWS_REGION=us-west-2
|
||||
|
||||
The endpoints package includes constants for all regions the SDK knows. The
|
||||
values are all suffixed with RegionID. These values are helpful, because they
|
||||
reduce the need to type the region string manually.
|
||||
|
||||
To set the region on a Session use the aws package's Config struct parameter
|
||||
Region to the AWS region you want the service clients created from the session to
|
||||
use. This is helpful when you want to create multiple service clients, and
|
||||
all of the clients make API requests to the same region.
|
||||
|
||||
```go
|
||||
sess := session.Must(session.NewSession(&aws.Config{
|
||||
Region: aws.String(endpoints.UsWest2RegionID),
|
||||
}))
|
||||
```
|
||||
|
||||
See the [endpoints][endpoints_pkg] package for the AWS Regions and Endpoints metadata.
|
||||
|
||||
In addition to setting the region when creating a Session you can also set
|
||||
the region on a per service client bases. This overrides the region of a
|
||||
Session. This is helpful when you want to create service clients in specific
|
||||
regions different from the Session's region.
|
||||
|
||||
```go
|
||||
svc := s3.New(sess, &aws.Config{
|
||||
Region: aws.String(endpoints.UsWest2RegionID),
|
||||
})
|
||||
```
|
||||
|
||||
See the [Config][config_typ] type in the [aws][aws_pkg] package for more information and additional
|
||||
options such as setting the Endpoint, and other service client configuration options.
|
||||
|
||||
[endpoints_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/
|
||||
|
||||
## Making API Requests
|
||||
|
||||
Once the client is created you can make an API request to the service.
|
||||
Each API method takes a input parameter, and returns the service response
|
||||
and an error. The SDK provides methods for making the API call in multiple ways.
|
||||
|
||||
In this list we'll use the S3 ListObjects API as an example for the different
|
||||
ways of making API requests.
|
||||
|
||||
* ListObjects - Base API operation that will make the API request to the service.
|
||||
|
||||
* ListObjectsRequest - API methods suffixed with Request will construct the
|
||||
API request, but not send it. This is also helpful when you want to get a
|
||||
presigned URL for a request, and share the presigned URL instead of your
|
||||
application making the request directly.
|
||||
|
||||
* ListObjectsPages - Same as the base API operation, but uses a callback to
|
||||
automatically handle pagination of the API's response.
|
||||
|
||||
* ListObjectsWithContext - Same as base API operation, but adds support for
|
||||
the Context pattern. This is helpful for controlling the canceling of in
|
||||
flight requests. See the Go standard library context package for more
|
||||
information. This method also takes request package's Option functional
|
||||
options as the variadic argument for modifying how the request will be
|
||||
made, or extracting information from the raw HTTP response.
|
||||
|
||||
* ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for
|
||||
the Context pattern. Similar to ListObjectsWithContext this method also
|
||||
takes the request package's Option function option types as the variadic
|
||||
argument.
|
||||
|
||||
In addition to the API operations the SDK also includes several higher level
|
||||
methods that abstract checking for and waiting for an AWS resource to be in
|
||||
a desired state. In this list we'll use WaitUntilBucketExists to demonstrate
|
||||
the different forms of waiters.
|
||||
|
||||
* WaitUntilBucketExists. - Method to make API request to query an AWS service for
|
||||
a resource's state. Will return successfully when that state is accomplished.
|
||||
|
||||
* WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds
|
||||
support for the Context pattern. In addition these methods take request
|
||||
package's WaiterOptions to configure the waiter, and how underlying request
|
||||
will be made by the SDK.
|
||||
|
||||
The API method will document which error codes the service might return for
|
||||
the operation. These errors will also be available as const strings prefixed
|
||||
with "ErrCode" in the service client's package. If there are no errors listed
|
||||
in the API's SDK documentation you'll need to consult the AWS service's API
|
||||
documentation for the errors that could be returned.
|
||||
|
||||
```go
|
||||
ctx := context.Background()
|
||||
|
||||
result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{
|
||||
Bucket: aws.String("my-bucket"),
|
||||
Key: aws.String("my-key"),
|
||||
})
|
||||
if err != nil {
|
||||
// Cast err to awserr.Error to handle specific error codes.
|
||||
aerr, ok := err.(awserr.Error)
|
||||
if ok && aerr.Code() == s3.ErrCodeNoSuchKey {
|
||||
// Specific error code handling
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure to close the body when done with it for S3 GetObject APIs or
|
||||
// will leak connections.
|
||||
defer result.Body.Close()
|
||||
|
||||
fmt.Println("Object Size:", aws.StringValue(result.ContentLength))
|
||||
```
|
||||
|
||||
### API Request Pagination and Resource Waiters
|
||||
|
||||
Pagination helper methods are suffixed with "Pages", and provide the
|
||||
functionality needed to round trip API page requests. Pagination methods
|
||||
take a callback function that will be called for each page of the API's response.
|
||||
|
||||
```go
|
||||
objects := []string{}
|
||||
err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{
|
||||
Bucket: aws.String(myBucket),
|
||||
}, func(p *s3.ListObjectsOutput, lastPage bool) bool {
|
||||
for _, o := range p.Contents {
|
||||
objects = append(objects, aws.StringValue(o.Key))
|
||||
}
|
||||
return true // continue paging
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err))
|
||||
}
|
||||
|
||||
fmt.Println("Objects in bucket:", objects)
|
||||
```
|
||||
|
||||
Waiter helper methods provide the functionality to wait for an AWS resource
|
||||
state. These methods abstract the logic needed to to check the state of an
|
||||
AWS resource, and wait until that resource is in a desired state. The waiter
|
||||
will block until the resource is in the state that is desired, an error occurs,
|
||||
or the waiter times out. If a resource times out the error code returned will
|
||||
be request.WaiterResourceNotReadyErrorCode.
|
||||
|
||||
```go
|
||||
err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{
|
||||
Bucket: aws.String(myBucket),
|
||||
})
|
||||
if err != nil {
|
||||
aerr, ok := err.(awserr.Error)
|
||||
if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode {
|
||||
fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist")
|
||||
}
|
||||
panic(fmt.Errorf("failed to wait for bucket to exist, %v", err))
|
||||
}
|
||||
fmt.Println("Bucket", myBucket, "exists")
|
||||
```
|
||||
|
||||
## Complete SDK Example
|
||||
|
||||
This example shows a complete working Go file which will upload a file to S3
|
||||
and use the Context pattern to implement timeout logic that will cancel the
|
||||
request if it takes too long. This example highlights how to use sessions,
|
||||
create a service client, make a request, handle the error, and process the
|
||||
response.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
// Uploads a file to S3 given a bucket and object key. Also takes a duration
|
||||
// value to terminate the update if it doesn't complete within that time.
|
||||
//
|
||||
// The AWS Region needs to be provided in the AWS shared config or on the
|
||||
// environment variable as `AWS_REGION`. Credentials also must be provided
|
||||
// Will default to shared config file, but can load from environment if provided.
|
||||
//
|
||||
// Usage:
|
||||
// # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
|
||||
// go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt
|
||||
func main() {
|
||||
var bucket, key string
|
||||
var timeout time.Duration
|
||||
|
||||
flag.StringVar(&bucket, "b", "", "Bucket name.")
|
||||
flag.StringVar(&key, "k", "", "Object key name.")
|
||||
flag.DurationVar(&timeout, "d", 0, "Upload timeout.")
|
||||
flag.Parse()
|
||||
|
||||
// All clients require a Session. The Session provides the client with
|
||||
// shared configuration such as region, endpoint, and credentials. A
|
||||
// Session should be shared where possible to take advantage of
|
||||
// configuration and credential caching. See the session package for
|
||||
// more information.
|
||||
sess := session.Must(session.NewSession())
|
||||
|
||||
// Create a new instance of the service's client with a Session.
|
||||
// Optional aws.Config values can also be provided as variadic arguments
|
||||
// to the New function. This option allows you to provide service
|
||||
// specific configuration.
|
||||
svc := s3.New(sess)
|
||||
|
||||
// Create a context with a timeout that will abort the upload if it takes
|
||||
// more than the passed in timeout.
|
||||
ctx := context.Background()
|
||||
var cancelFn func()
|
||||
if timeout > 0 {
|
||||
ctx, cancelFn = context.WithTimeout(ctx, timeout)
|
||||
}
|
||||
// Ensure the context is canceled to prevent leaking.
|
||||
// See context package for more information, https://golang.org/pkg/context/
|
||||
defer cancelFn()
|
||||
|
||||
// Uploads the object to S3. The Context will interrupt the request if the
|
||||
// timeout expires.
|
||||
_, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: aws.String(key),
|
||||
Body: os.Stdin,
|
||||
})
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
|
||||
// If the SDK can determine the request or retry delay was canceled
|
||||
// by a context the CanceledErrorCode error code will be returned.
|
||||
fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key)
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This SDK is distributed under the
|
||||
[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0),
|
||||
see LICENSE.txt and NOTICE.txt for more information.
|
86
vendor/github.com/aws/aws-sdk-go/aws/arn/arn.go
generated
vendored
86
vendor/github.com/aws/aws-sdk-go/aws/arn/arn.go
generated
vendored
|
@ -1,86 +0,0 @@
|
|||
// Package arn provides a parser for interacting with Amazon Resource Names.
|
||||
package arn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
arnDelimiter = ":"
|
||||
arnSections = 6
|
||||
arnPrefix = "arn:"
|
||||
|
||||
// zero-indexed
|
||||
sectionPartition = 1
|
||||
sectionService = 2
|
||||
sectionRegion = 3
|
||||
sectionAccountID = 4
|
||||
sectionResource = 5
|
||||
|
||||
// errors
|
||||
invalidPrefix = "arn: invalid prefix"
|
||||
invalidSections = "arn: not enough sections"
|
||||
)
|
||||
|
||||
// ARN captures the individual fields of an Amazon Resource Name.
|
||||
// See http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html for more information.
|
||||
type ARN struct {
|
||||
// The partition that the resource is in. For standard AWS regions, the partition is "aws". If you have resources in
|
||||
// other partitions, the partition is "aws-partitionname". For example, the partition for resources in the China
|
||||
// (Beijing) region is "aws-cn".
|
||||
Partition string
|
||||
|
||||
// The service namespace that identifies the AWS product (for example, Amazon S3, IAM, or Amazon RDS). For a list of
|
||||
// namespaces, see
|
||||
// http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces.
|
||||
Service string
|
||||
|
||||
// The region the resource resides in. Note that the ARNs for some resources do not require a region, so this
|
||||
// component might be omitted.
|
||||
Region string
|
||||
|
||||
// The ID of the AWS account that owns the resource, without the hyphens. For example, 123456789012. Note that the
|
||||
// ARNs for some resources don't require an account number, so this component might be omitted.
|
||||
AccountID string
|
||||
|
||||
// The content of this part of the ARN varies by service. It often includes an indicator of the type of resource —
|
||||
// for example, an IAM user or Amazon RDS database - followed by a slash (/) or a colon (:), followed by the
|
||||
// resource name itself. Some services allows paths for resource names, as described in
|
||||
// http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arns-paths.
|
||||
Resource string
|
||||
}
|
||||
|
||||
// Parse parses an ARN into its constituent parts.
|
||||
//
|
||||
// Some example ARNs:
|
||||
// arn:aws:elasticbeanstalk:us-east-1:123456789012:environment/My App/MyEnvironment
|
||||
// arn:aws:iam::123456789012:user/David
|
||||
// arn:aws:rds:eu-west-1:123456789012:db:mysql-db
|
||||
// arn:aws:s3:::my_corporate_bucket/exampleobject.png
|
||||
func Parse(arn string) (ARN, error) {
|
||||
if !strings.HasPrefix(arn, arnPrefix) {
|
||||
return ARN{}, errors.New(invalidPrefix)
|
||||
}
|
||||
sections := strings.SplitN(arn, arnDelimiter, arnSections)
|
||||
if len(sections) != arnSections {
|
||||
return ARN{}, errors.New(invalidSections)
|
||||
}
|
||||
return ARN{
|
||||
Partition: sections[sectionPartition],
|
||||
Service: sections[sectionService],
|
||||
Region: sections[sectionRegion],
|
||||
AccountID: sections[sectionAccountID],
|
||||
Resource: sections[sectionResource],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the canonical representation of the ARN
|
||||
func (arn ARN) String() string {
|
||||
return arnPrefix +
|
||||
arn.Partition + arnDelimiter +
|
||||
arn.Service + arnDelimiter +
|
||||
arn.Region + arnDelimiter +
|
||||
arn.AccountID + arnDelimiter +
|
||||
arn.Resource
|
||||
}
|
90
vendor/github.com/aws/aws-sdk-go/aws/arn/arn_test.go
generated
vendored
90
vendor/github.com/aws/aws-sdk-go/aws/arn/arn_test.go
generated
vendored
|
@ -1,90 +0,0 @@
|
|||
// +build go1.7
|
||||
|
||||
package arn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseARN(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
arn ARN
|
||||
err error
|
||||
}{
|
||||
{
|
||||
input: "invalid",
|
||||
err: errors.New(invalidPrefix),
|
||||
},
|
||||
{
|
||||
input: "arn:nope",
|
||||
err: errors.New(invalidSections),
|
||||
},
|
||||
{
|
||||
input: "arn:aws:ecr:us-west-2:123456789012:repository/foo/bar",
|
||||
arn: ARN{
|
||||
Partition: "aws",
|
||||
Service: "ecr",
|
||||
Region: "us-west-2",
|
||||
AccountID: "123456789012",
|
||||
Resource: "repository/foo/bar",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "arn:aws:elasticbeanstalk:us-east-1:123456789012:environment/My App/MyEnvironment",
|
||||
arn: ARN{
|
||||
Partition: "aws",
|
||||
Service: "elasticbeanstalk",
|
||||
Region: "us-east-1",
|
||||
AccountID: "123456789012",
|
||||
Resource: "environment/My App/MyEnvironment",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "arn:aws:iam::123456789012:user/David",
|
||||
arn: ARN{
|
||||
Partition: "aws",
|
||||
Service: "iam",
|
||||
Region: "",
|
||||
AccountID: "123456789012",
|
||||
Resource: "user/David",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "arn:aws:rds:eu-west-1:123456789012:db:mysql-db",
|
||||
arn: ARN{
|
||||
Partition: "aws",
|
||||
Service: "rds",
|
||||
Region: "eu-west-1",
|
||||
AccountID: "123456789012",
|
||||
Resource: "db:mysql-db",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "arn:aws:s3:::my_corporate_bucket/exampleobject.png",
|
||||
arn: ARN{
|
||||
Partition: "aws",
|
||||
Service: "s3",
|
||||
Region: "",
|
||||
AccountID: "",
|
||||
Resource: "my_corporate_bucket/exampleobject.png",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.input, func(t *testing.T) {
|
||||
spec, err := Parse(tc.input)
|
||||
if tc.arn != spec {
|
||||
t.Errorf("Expected %q to parse as %v, but got %v", tc.input, tc.arn, spec)
|
||||
}
|
||||
if err == nil && tc.err != nil {
|
||||
t.Errorf("Expected err to be %v, but got nil", tc.err)
|
||||
} else if err != nil && tc.err == nil {
|
||||
t.Errorf("Expected err to be nil, but got %v", err)
|
||||
} else if err != nil && tc.err != nil && err.Error() != tc.err.Error() {
|
||||
t.Errorf("Expected err to be %v, but got %v", tc.err, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
23
vendor/github.com/aws/aws-sdk-go/aws/awserr/error.go
generated
vendored
23
vendor/github.com/aws/aws-sdk-go/aws/awserr/error.go
generated
vendored
|
@ -138,8 +138,27 @@ type RequestFailure interface {
|
|||
RequestID() string
|
||||
}
|
||||
|
||||
// NewRequestFailure returns a new request error wrapper for the given Error
|
||||
// provided.
|
||||
// NewRequestFailure returns a wrapped error with additional information for
|
||||
// request status code, and service requestID.
|
||||
//
|
||||
// Should be used to wrap all request which involve service requests. Even if
|
||||
// the request failed without a service response, but had an HTTP status code
|
||||
// that may be meaningful.
|
||||
func NewRequestFailure(err Error, statusCode int, reqID string) RequestFailure {
|
||||
return newRequestError(err, statusCode, reqID)
|
||||
}
|
||||
|
||||
// UnmarshalError provides the interface for the SDK failing to unmarshal data.
|
||||
type UnmarshalError interface {
|
||||
awsError
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
// NewUnmarshalError returns an initialized UnmarshalError error wrapper adding
|
||||
// the bytes that fail to unmarshal to the error.
|
||||
func NewUnmarshalError(err error, msg string, bytes []byte) UnmarshalError {
|
||||
return &unmarshalError{
|
||||
awsError: New("UnmarshalError", msg, err),
|
||||
bytes: bytes,
|
||||
}
|
||||
}
|
||||
|
|
29
vendor/github.com/aws/aws-sdk-go/aws/awserr/types.go
generated
vendored
29
vendor/github.com/aws/aws-sdk-go/aws/awserr/types.go
generated
vendored
|
@ -1,6 +1,9 @@
|
|||
package awserr
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// SprintError returns a string of the formatted error code.
|
||||
//
|
||||
|
@ -119,6 +122,7 @@ type requestError struct {
|
|||
awsError
|
||||
statusCode int
|
||||
requestID string
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
// newRequestError returns a wrapped error with additional information for
|
||||
|
@ -170,6 +174,29 @@ func (r requestError) OrigErrs() []error {
|
|||
return []error{r.OrigErr()}
|
||||
}
|
||||
|
||||
type unmarshalError struct {
|
||||
awsError
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
// Satisfies the error interface.
|
||||
func (e unmarshalError) Error() string {
|
||||
extra := hex.Dump(e.bytes)
|
||||
return SprintError(e.Code(), e.Message(), extra, e.OrigErr())
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
// Alias for Error to satisfy the stringer interface.
|
||||
func (e unmarshalError) String() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
// Bytes returns the bytes that failed to unmarshal.
|
||||
func (e unmarshalError) Bytes() []byte {
|
||||
return e.bytes
|
||||
}
|
||||
|
||||
// An error list that satisfies the golang interface
|
||||
type errorList []error
|
||||
|
||||
|
|
353
vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy_test.go
generated
vendored
353
vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy_test.go
generated
vendored
|
@ -1,353 +0,0 @@
|
|||
package awsutil_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
)
|
||||
|
||||
func ExampleCopy() {
|
||||
type Foo struct {
|
||||
A int
|
||||
B []*string
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
f1 := &Foo{A: 1, B: []*string{&str1, &str2}}
|
||||
|
||||
// Do the copy
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Print the result
|
||||
fmt.Println(awsutil.Prettify(f2))
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// A: 1,
|
||||
// B: ["hello","bye bye"]
|
||||
// }
|
||||
}
|
||||
|
||||
func TestCopy1(t *testing.T) {
|
||||
type Bar struct {
|
||||
a *int
|
||||
B *int
|
||||
c int
|
||||
D int
|
||||
}
|
||||
type Foo struct {
|
||||
A int
|
||||
B []*string
|
||||
C map[string]*int
|
||||
D *time.Time
|
||||
E *Bar
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
int1 := 1
|
||||
int2 := 2
|
||||
intPtr1 := 1
|
||||
intPtr2 := 2
|
||||
now := time.Now()
|
||||
f1 := &Foo{
|
||||
A: 1,
|
||||
B: []*string{&str1, &str2},
|
||||
C: map[string]*int{
|
||||
"A": &int1,
|
||||
"B": &int2,
|
||||
},
|
||||
D: &now,
|
||||
E: &Bar{
|
||||
&intPtr1,
|
||||
&intPtr2,
|
||||
2,
|
||||
3,
|
||||
},
|
||||
}
|
||||
|
||||
// Do the copy
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Values are equal
|
||||
if v1, v2 := f2.A, f1.A; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.B, f1.B; !reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.C, f1.C; !reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.D, f1.D; !v1.Equal(*v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.E.B, f1.E.B; !reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.E.D, f1.E.D; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
|
||||
// But pointers are not!
|
||||
str3 := "nothello"
|
||||
int3 := 57
|
||||
f2.A = 100
|
||||
*f2.B[0] = str3
|
||||
*f2.C["B"] = int3
|
||||
*f2.D = time.Now()
|
||||
f2.E.a = &int3
|
||||
*f2.E.B = int3
|
||||
f2.E.c = 5
|
||||
f2.E.D = 5
|
||||
if v1, v2 := f2.A, f1.A; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.B, f1.B; reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.C, f1.C; reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.D, f1.D; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.E.a, f1.E.a; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.E.B, f1.E.B; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.E.c, f1.E.c; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.E.D, f1.E.D; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyNestedWithUnexported(t *testing.T) {
|
||||
type Bar struct {
|
||||
a int
|
||||
B int
|
||||
}
|
||||
type Foo struct {
|
||||
A string
|
||||
B Bar
|
||||
}
|
||||
|
||||
f1 := &Foo{A: "string", B: Bar{a: 1, B: 2}}
|
||||
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Values match
|
||||
if v1, v2 := f2.A, f1.A; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.B, f1.B; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.B.a, f1.B.a; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.B.B, f2.B.B; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyIgnoreNilMembers(t *testing.T) {
|
||||
type Foo struct {
|
||||
A *string
|
||||
B []string
|
||||
C map[string]string
|
||||
}
|
||||
|
||||
f := &Foo{}
|
||||
if v1 := f.A; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f.B; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f.C; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f)
|
||||
if v1 := f2.A; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f2.B; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f2.C; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
|
||||
fcopy := awsutil.CopyOf(f)
|
||||
f3 := fcopy.(*Foo)
|
||||
if v1 := f3.A; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f3.B; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f3.C; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyPrimitive(t *testing.T) {
|
||||
str := "hello"
|
||||
var s string
|
||||
awsutil.Copy(&s, &str)
|
||||
if v1, v2 := "hello", s; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyNil(t *testing.T) {
|
||||
var s string
|
||||
awsutil.Copy(&s, nil)
|
||||
if v1, v2 := "", s; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyReader(t *testing.T) {
|
||||
var buf io.Reader = bytes.NewReader([]byte("hello world"))
|
||||
var r io.Reader
|
||||
awsutil.Copy(&r, buf)
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, but received %v", err)
|
||||
}
|
||||
if v1, v2 := []byte("hello world"), b; !bytes.Equal(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
|
||||
// empty bytes because this is not a deep copy
|
||||
b, err = ioutil.ReadAll(buf)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, but received %v", err)
|
||||
}
|
||||
if v1, v2 := []byte(""), b; !bytes.Equal(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyDifferentStructs(t *testing.T) {
|
||||
type SrcFoo struct {
|
||||
A int
|
||||
B []*string
|
||||
C map[string]*int
|
||||
SrcUnique string
|
||||
SameNameDiffType int
|
||||
unexportedPtr *int
|
||||
ExportedPtr *int
|
||||
}
|
||||
type DstFoo struct {
|
||||
A int
|
||||
B []*string
|
||||
C map[string]*int
|
||||
DstUnique int
|
||||
SameNameDiffType string
|
||||
unexportedPtr *int
|
||||
ExportedPtr *int
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
int1 := 1
|
||||
int2 := 2
|
||||
f1 := &SrcFoo{
|
||||
A: 1,
|
||||
B: []*string{&str1, &str2},
|
||||
C: map[string]*int{
|
||||
"A": &int1,
|
||||
"B": &int2,
|
||||
},
|
||||
SrcUnique: "unique",
|
||||
SameNameDiffType: 1,
|
||||
unexportedPtr: &int1,
|
||||
ExportedPtr: &int2,
|
||||
}
|
||||
|
||||
// Do the copy
|
||||
var f2 DstFoo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Values are equal
|
||||
if v1, v2 := f2.A, f1.A; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.B, f1.B; !reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.C, f1.C; !reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := "unique", f1.SrcUnique; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := 1, f1.SameNameDiffType; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := 0, f2.DstUnique; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := "", f2.SameNameDiffType; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := int1, *f1.unexportedPtr; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1 := f2.unexportedPtr; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := int2, *f1.ExportedPtr; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := int2, *f2.ExportedPtr; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleCopyOf() {
|
||||
type Foo struct {
|
||||
A int
|
||||
B []*string
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
f1 := &Foo{A: 1, B: []*string{&str1, &str2}}
|
||||
|
||||
// Do the copy
|
||||
v := awsutil.CopyOf(f1)
|
||||
var f2 *Foo = v.(*Foo)
|
||||
|
||||
// Print the result
|
||||
fmt.Println(awsutil.Prettify(f2))
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// A: 1,
|
||||
// B: ["hello","bye bye"]
|
||||
// }
|
||||
}
|
2
vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go
generated
vendored
|
@ -15,7 +15,7 @@ func DeepEqual(a, b interface{}) bool {
|
|||
rb := reflect.Indirect(reflect.ValueOf(b))
|
||||
|
||||
if raValid, rbValid := ra.IsValid(), rb.IsValid(); !raValid && !rbValid {
|
||||
// If the elements are both nil, and of the same type the are equal
|
||||
// If the elements are both nil, and of the same type they are equal
|
||||
// If they are of different types they are not equal
|
||||
return reflect.TypeOf(a) == reflect.TypeOf(b)
|
||||
} else if raValid != rbValid {
|
||||
|
|
30
vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal_test.go
generated
vendored
30
vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal_test.go
generated
vendored
|
@ -1,30 +0,0 @@
|
|||
package awsutil_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
)
|
||||
|
||||
func TestDeepEqual(t *testing.T) {
|
||||
cases := []struct {
|
||||
a, b interface{}
|
||||
equal bool
|
||||
}{
|
||||
{"a", "a", true},
|
||||
{"a", "b", false},
|
||||
{"a", aws.String(""), false},
|
||||
{"a", nil, false},
|
||||
{"a", aws.String("a"), true},
|
||||
{(*bool)(nil), (*bool)(nil), true},
|
||||
{(*bool)(nil), (*string)(nil), false},
|
||||
{nil, nil, true},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
if awsutil.DeepEqual(c.a, c.b) != c.equal {
|
||||
t.Errorf("%d, a:%v b:%v, %t", i, c.a, c.b, c.equal)
|
||||
}
|
||||
}
|
||||
}
|
182
vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value_test.go
generated
vendored
182
vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value_test.go
generated
vendored
|
@ -1,182 +0,0 @@
|
|||
package awsutil_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
)
|
||||
|
||||
type Struct struct {
|
||||
A []Struct
|
||||
z []Struct
|
||||
B *Struct
|
||||
D *Struct
|
||||
C string
|
||||
E map[string]string
|
||||
}
|
||||
|
||||
var data = Struct{
|
||||
A: []Struct{{C: "value1"}, {C: "value2"}, {C: "value3"}},
|
||||
z: []Struct{{C: "value1"}, {C: "value2"}, {C: "value3"}},
|
||||
B: &Struct{B: &Struct{C: "terminal"}, D: &Struct{C: "terminal2"}},
|
||||
C: "initial",
|
||||
}
|
||||
var data2 = Struct{A: []Struct{
|
||||
{A: []Struct{{C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}}},
|
||||
{A: []Struct{{C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}}},
|
||||
}}
|
||||
|
||||
func TestValueAtPathSuccess(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
expect []interface{}
|
||||
data interface{}
|
||||
path string
|
||||
}{
|
||||
{[]interface{}{"initial"}, data, "C"},
|
||||
{[]interface{}{"value1"}, data, "A[0].C"},
|
||||
{[]interface{}{"value2"}, data, "A[1].C"},
|
||||
{[]interface{}{"value3"}, data, "A[2].C"},
|
||||
{[]interface{}{"value3"}, data, "a[2].c"},
|
||||
{[]interface{}{"value3"}, data, "A[-1].C"},
|
||||
{[]interface{}{"value1", "value2", "value3"}, data, "A[].C"},
|
||||
{[]interface{}{"terminal"}, data, "B . B . C"},
|
||||
{[]interface{}{"initial"}, data, "A.D.X || C"},
|
||||
{[]interface{}{"initial"}, data, "A[0].B || C"},
|
||||
{[]interface{}{
|
||||
Struct{A: []Struct{{C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}}},
|
||||
Struct{A: []Struct{{C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}}},
|
||||
}, data2, "A"},
|
||||
}
|
||||
for i, c := range testCases {
|
||||
v, err := awsutil.ValuesAtPath(c.data, c.path)
|
||||
if err != nil {
|
||||
t.Errorf("case %v, expected no error, %v", i, c.path)
|
||||
}
|
||||
if e, a := c.expect, v; !awsutil.DeepEqual(e, a) {
|
||||
t.Errorf("case %v, %v", i, c.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueAtPathFailure(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
expect []interface{}
|
||||
errContains string
|
||||
data interface{}
|
||||
path string
|
||||
}{
|
||||
{nil, "", data, "C.x"},
|
||||
{nil, "SyntaxError: Invalid token: tDot", data, ".x"},
|
||||
{nil, "", data, "X.Y.Z"},
|
||||
{nil, "", data, "A[100].C"},
|
||||
{nil, "", data, "A[3].C"},
|
||||
{nil, "", data, "B.B.C.Z"},
|
||||
{nil, "", data, "z[-1].C"},
|
||||
{nil, "", nil, "A.B.C"},
|
||||
{[]interface{}{}, "", Struct{}, "A"},
|
||||
{nil, "", data, "A[0].B.C"},
|
||||
{nil, "", data, "D"},
|
||||
}
|
||||
|
||||
for i, c := range testCases {
|
||||
v, err := awsutil.ValuesAtPath(c.data, c.path)
|
||||
if c.errContains != "" {
|
||||
if !strings.Contains(err.Error(), c.errContains) {
|
||||
t.Errorf("case %v, expected error, %v", i, c.path)
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("case %v, expected no error, %v", i, c.path)
|
||||
}
|
||||
}
|
||||
if e, a := c.expect, v; !awsutil.DeepEqual(e, a) {
|
||||
t.Errorf("case %v, %v", i, c.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetValueAtPathSuccess(t *testing.T) {
|
||||
var s Struct
|
||||
awsutil.SetValueAtPath(&s, "C", "test1")
|
||||
awsutil.SetValueAtPath(&s, "B.B.C", "test2")
|
||||
awsutil.SetValueAtPath(&s, "B.D.C", "test3")
|
||||
if e, a := "test1", s.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
if e, a := "test2", s.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
if e, a := "test3", s.B.D.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
awsutil.SetValueAtPath(&s, "B.*.C", "test0")
|
||||
if e, a := "test0", s.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
if e, a := "test0", s.B.D.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
var s2 Struct
|
||||
awsutil.SetValueAtPath(&s2, "b.b.c", "test0")
|
||||
if e, a := "test0", s2.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
awsutil.SetValueAtPath(&s2, "A", []Struct{{}})
|
||||
if e, a := []Struct{{}}, s2.A; !awsutil.DeepEqual(e, a) {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
str := "foo"
|
||||
|
||||
s3 := Struct{}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", str)
|
||||
if e, a := "foo", s3.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s3 = Struct{B: &Struct{B: &Struct{C: str}}}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", nil)
|
||||
if e, a := "", s3.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s3 = Struct{}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", nil)
|
||||
if e, a := "", s3.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s3 = Struct{}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", &str)
|
||||
if e, a := "foo", s3.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
var s4 struct{ Name *string }
|
||||
awsutil.SetValueAtPath(&s4, "Name", str)
|
||||
if e, a := str, *s4.Name; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s4 = struct{ Name *string }{}
|
||||
awsutil.SetValueAtPath(&s4, "Name", nil)
|
||||
if e, a := (*string)(nil), s4.Name; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s4 = struct{ Name *string }{Name: &str}
|
||||
awsutil.SetValueAtPath(&s4, "Name", nil)
|
||||
if e, a := (*string)(nil), s4.Name; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s4 = struct{ Name *string }{}
|
||||
awsutil.SetValueAtPath(&s4, "Name", &str)
|
||||
if e, a := str, *s4.Name; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
}
|
25
vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go
generated
vendored
25
vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go
generated
vendored
|
@ -23,28 +23,27 @@ func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) {
|
|||
case reflect.Struct:
|
||||
buf.WriteString("{\n")
|
||||
|
||||
names := []string{}
|
||||
for i := 0; i < v.Type().NumField(); i++ {
|
||||
name := v.Type().Field(i).Name
|
||||
f := v.Field(i)
|
||||
if name[0:1] == strings.ToLower(name[0:1]) {
|
||||
ft := v.Type().Field(i)
|
||||
fv := v.Field(i)
|
||||
|
||||
if ft.Name[0:1] == strings.ToLower(ft.Name[0:1]) {
|
||||
continue // ignore unexported fields
|
||||
}
|
||||
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice) && f.IsNil() {
|
||||
if (fv.Kind() == reflect.Ptr || fv.Kind() == reflect.Slice) && fv.IsNil() {
|
||||
continue // ignore unset fields
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
for i, n := range names {
|
||||
val := v.FieldByName(n)
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString(n + ": ")
|
||||
stringValue(val, indent+2, buf)
|
||||
buf.WriteString(ft.Name + ": ")
|
||||
|
||||
if i < len(names)-1 {
|
||||
buf.WriteString(",\n")
|
||||
if tag := ft.Tag.Get("sensitive"); tag == "true" {
|
||||
buf.WriteString("<sensitive>")
|
||||
} else {
|
||||
stringValue(fv, indent+2, buf)
|
||||
}
|
||||
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
|
||||
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||
|
|
10
vendor/github.com/aws/aws-sdk-go/aws/client/client.go
generated
vendored
10
vendor/github.com/aws/aws-sdk-go/aws/client/client.go
generated
vendored
|
@ -15,6 +15,12 @@ type Config struct {
|
|||
Endpoint string
|
||||
SigningRegion string
|
||||
SigningName string
|
||||
|
||||
// States that the signing name did not come from a modeled source but
|
||||
// was derived based on other data. Used by service client constructors
|
||||
// to determine if the signin name can be overridden based on metadata the
|
||||
// service has.
|
||||
SigningNameDerived bool
|
||||
}
|
||||
|
||||
// ConfigProvider provides a generic way for a service client to receive
|
||||
|
@ -85,6 +91,6 @@ func (c *Client) AddDebugHandlers() {
|
|||
return
|
||||
}
|
||||
|
||||
c.Handlers.Send.PushFrontNamed(request.NamedHandler{Name: "awssdk.client.LogRequest", Fn: logRequest})
|
||||
c.Handlers.Send.PushBackNamed(request.NamedHandler{Name: "awssdk.client.LogResponse", Fn: logResponse})
|
||||
c.Handlers.Send.PushFrontNamed(LogHTTPRequestHandler)
|
||||
c.Handlers.Send.PushBackNamed(LogHTTPResponseHandler)
|
||||
}
|
||||
|
|
78
vendor/github.com/aws/aws-sdk-go/aws/client/client_test.go
generated
vendored
78
vendor/github.com/aws/aws-sdk-go/aws/client/client_test.go
generated
vendored
|
@ -1,78 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
func pushBackTestHandler(name string, list *request.HandlerList) *bool {
|
||||
called := false
|
||||
(*list).PushBackNamed(request.NamedHandler{
|
||||
Name: name,
|
||||
Fn: func(r *request.Request) {
|
||||
called = true
|
||||
},
|
||||
})
|
||||
|
||||
return &called
|
||||
}
|
||||
|
||||
func pushFrontTestHandler(name string, list *request.HandlerList) *bool {
|
||||
called := false
|
||||
(*list).PushFrontNamed(request.NamedHandler{
|
||||
Name: name,
|
||||
Fn: func(r *request.Request) {
|
||||
called = true
|
||||
},
|
||||
})
|
||||
|
||||
return &called
|
||||
}
|
||||
|
||||
func TestNewClient_CopyHandlers(t *testing.T) {
|
||||
handlers := request.Handlers{}
|
||||
firstCalled := pushBackTestHandler("first", &handlers.Send)
|
||||
secondCalled := pushBackTestHandler("second", &handlers.Send)
|
||||
|
||||
var clientHandlerCalled *bool
|
||||
c := New(aws.Config{}, metadata.ClientInfo{}, handlers,
|
||||
func(c *Client) {
|
||||
clientHandlerCalled = pushFrontTestHandler("client handler", &c.Handlers.Send)
|
||||
},
|
||||
)
|
||||
|
||||
if e, a := 2, handlers.Send.Len(); e != a {
|
||||
t.Errorf("expect %d original handlers, got %d", e, a)
|
||||
}
|
||||
if e, a := 3, c.Handlers.Send.Len(); e != a {
|
||||
t.Errorf("expect %d client handlers, got %d", e, a)
|
||||
}
|
||||
|
||||
handlers.Send.Run(nil)
|
||||
if !*firstCalled {
|
||||
t.Errorf("expect first handler to of been called")
|
||||
}
|
||||
*firstCalled = false
|
||||
if !*secondCalled {
|
||||
t.Errorf("expect second handler to of been called")
|
||||
}
|
||||
*secondCalled = false
|
||||
if *clientHandlerCalled {
|
||||
t.Errorf("expect client handler to not of been called, but was")
|
||||
}
|
||||
|
||||
c.Handlers.Send.Run(nil)
|
||||
if !*firstCalled {
|
||||
t.Errorf("expect client's first handler to of been called")
|
||||
}
|
||||
if !*secondCalled {
|
||||
t.Errorf("expect client's second handler to of been called")
|
||||
}
|
||||
if !*clientHandlerCalled {
|
||||
t.Errorf("expect client's client handler to of been called")
|
||||
}
|
||||
|
||||
}
|
28
vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go
generated
vendored
28
vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go
generated
vendored
|
@ -1,12 +1,11 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/internal/sdkrand"
|
||||
)
|
||||
|
||||
// DefaultRetryer implements basic retry logic using exponential backoff for
|
||||
|
@ -31,8 +30,6 @@ func (d DefaultRetryer) MaxRetries() int {
|
|||
return d.NumMaxRetries
|
||||
}
|
||||
|
||||
var seededRand = rand.New(&lockedSource{src: rand.NewSource(time.Now().UnixNano())})
|
||||
|
||||
// RetryRules returns the delay duration before retrying this request again
|
||||
func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
|
||||
// Set the upper limit of delay in retrying at ~five minutes
|
||||
|
@ -53,7 +50,7 @@ func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
|
|||
retryCount = 13
|
||||
}
|
||||
|
||||
delay := (1 << uint(retryCount)) * (seededRand.Intn(minTime) + minTime)
|
||||
delay := (1 << uint(retryCount)) * (sdkrand.SeededRand.Intn(minTime) + minTime)
|
||||
return time.Duration(delay) * time.Millisecond
|
||||
}
|
||||
|
||||
|
@ -65,7 +62,7 @@ func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
|
|||
return *r.Retryable
|
||||
}
|
||||
|
||||
if r.HTTPResponse.StatusCode >= 500 {
|
||||
if r.HTTPResponse.StatusCode >= 500 && r.HTTPResponse.StatusCode != 501 {
|
||||
return true
|
||||
}
|
||||
return r.IsErrorRetryable() || d.shouldThrottle(r)
|
||||
|
@ -117,22 +114,3 @@ func canUseRetryAfterHeader(r *request.Request) bool {
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
// lockedSource is a thread-safe implementation of rand.Source
|
||||
type lockedSource struct {
|
||||
lk sync.Mutex
|
||||
src rand.Source
|
||||
}
|
||||
|
||||
func (r *lockedSource) Int63() (n int64) {
|
||||
r.lk.Lock()
|
||||
n = r.src.Int63()
|
||||
r.lk.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (r *lockedSource) Seed(seed int64) {
|
||||
r.lk.Lock()
|
||||
r.src.Seed(seed)
|
||||
r.lk.Unlock()
|
||||
}
|
||||
|
|
189
vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer_test.go
generated
vendored
189
vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer_test.go
generated
vendored
|
@ -1,189 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
func TestRetryThrottleStatusCodes(t *testing.T) {
|
||||
cases := []struct {
|
||||
expectThrottle bool
|
||||
expectRetry bool
|
||||
r request.Request
|
||||
}{
|
||||
{
|
||||
false,
|
||||
false,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 200},
|
||||
},
|
||||
},
|
||||
{
|
||||
true,
|
||||
true,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 429},
|
||||
},
|
||||
},
|
||||
{
|
||||
true,
|
||||
true,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 502},
|
||||
},
|
||||
},
|
||||
{
|
||||
true,
|
||||
true,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 503},
|
||||
},
|
||||
},
|
||||
{
|
||||
true,
|
||||
true,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 504},
|
||||
},
|
||||
},
|
||||
{
|
||||
false,
|
||||
true,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 500},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
d := DefaultRetryer{NumMaxRetries: 10}
|
||||
for i, c := range cases {
|
||||
throttle := d.shouldThrottle(&c.r)
|
||||
retry := d.ShouldRetry(&c.r)
|
||||
|
||||
if e, a := c.expectThrottle, throttle; e != a {
|
||||
t.Errorf("%d: expected %v, but received %v", i, e, a)
|
||||
}
|
||||
|
||||
if e, a := c.expectRetry, retry; e != a {
|
||||
t.Errorf("%d: expected %v, but received %v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanUseRetryAfter(t *testing.T) {
|
||||
cases := []struct {
|
||||
r request.Request
|
||||
e bool
|
||||
}{
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 200},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 500},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 429},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 503},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
a := canUseRetryAfterHeader(&c.r)
|
||||
if c.e != a {
|
||||
t.Errorf("%d: expected %v, but received %v", i, c.e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRetryDelay(t *testing.T) {
|
||||
cases := []struct {
|
||||
r request.Request
|
||||
e time.Duration
|
||||
equal bool
|
||||
ok bool
|
||||
}{
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 429, Header: http.Header{"Retry-After": []string{"3600"}}},
|
||||
},
|
||||
3600 * time.Second,
|
||||
true,
|
||||
true,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{"120"}}},
|
||||
},
|
||||
120 * time.Second,
|
||||
true,
|
||||
true,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{"120"}}},
|
||||
},
|
||||
1 * time.Second,
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{""}}},
|
||||
},
|
||||
0 * time.Second,
|
||||
true,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
a, ok := getRetryDelay(&c.r)
|
||||
if c.ok != ok {
|
||||
t.Errorf("%d: expected %v, but received %v", i, c.ok, ok)
|
||||
}
|
||||
|
||||
if (c.e != a) == c.equal {
|
||||
t.Errorf("%d: expected %v, but received %v", i, c.e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetryDelay(t *testing.T) {
|
||||
r := request.Request{}
|
||||
for i := 0; i < 100; i++ {
|
||||
rTemp := r
|
||||
rTemp.HTTPResponse = &http.Response{StatusCode: 500, Header: http.Header{"Retry-After": []string{""}}}
|
||||
rTemp.RetryCount = i
|
||||
a, _ := getRetryDelay(&rTemp)
|
||||
if a > 5*time.Minute {
|
||||
t.Errorf("retry delay should never be greater than five minutes, received %d", a)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
rTemp := r
|
||||
rTemp.RetryCount = i
|
||||
rTemp.HTTPResponse = &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{""}}}
|
||||
a, _ := getRetryDelay(&rTemp)
|
||||
if a > 5*time.Minute {
|
||||
t.Errorf("retry delay should never be greater than five minutes, received %d", a)
|
||||
}
|
||||
}
|
||||
}
|
112
vendor/github.com/aws/aws-sdk-go/aws/client/logger.go
generated
vendored
112
vendor/github.com/aws/aws-sdk-go/aws/client/logger.go
generated
vendored
|
@ -44,22 +44,57 @@ func (reader *teeReaderCloser) Close() error {
|
|||
return reader.Source.Close()
|
||||
}
|
||||
|
||||
// LogHTTPRequestHandler is a SDK request handler to log the HTTP request sent
|
||||
// to a service. Will include the HTTP request body if the LogLevel of the
|
||||
// request matches LogDebugWithHTTPBody.
|
||||
var LogHTTPRequestHandler = request.NamedHandler{
|
||||
Name: "awssdk.client.LogRequest",
|
||||
Fn: logRequest,
|
||||
}
|
||||
|
||||
func logRequest(r *request.Request) {
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, err := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
bodySeekable := aws.IsReaderSeekable(r.Body)
|
||||
|
||||
b, err := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
if err != nil {
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
if logBody {
|
||||
if !bodySeekable {
|
||||
r.SetReaderBody(aws.ReadSeekCloser(r.HTTPRequest.Body))
|
||||
}
|
||||
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
|
||||
// Body as a NoOpCloser and will not be reset after read by the HTTP
|
||||
// client reader.
|
||||
r.ResetBody()
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, string(b)))
|
||||
}
|
||||
|
||||
// LogHTTPRequestHeaderHandler is a SDK request handler to log the HTTP request sent
|
||||
// to a service. Will only log the HTTP request's headers. The request payload
|
||||
// will not be read.
|
||||
var LogHTTPRequestHeaderHandler = request.NamedHandler{
|
||||
Name: "awssdk.client.LogRequestHeader",
|
||||
Fn: logRequestHeader,
|
||||
}
|
||||
|
||||
func logRequestHeader(r *request.Request) {
|
||||
b, err := httputil.DumpRequestOut(r.HTTPRequest, false)
|
||||
if err != nil {
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, string(b)))
|
||||
}
|
||||
|
||||
const logRespMsg = `DEBUG: Response %s/%s Details:
|
||||
|
@ -72,27 +107,50 @@ const logRespErrMsg = `DEBUG ERROR: Response %s/%s:
|
|||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
// LogHTTPResponseHandler is a SDK request handler to log the HTTP response
|
||||
// received from a service. Will include the HTTP response body if the LogLevel
|
||||
// of the request matches LogDebugWithHTTPBody.
|
||||
var LogHTTPResponseHandler = request.NamedHandler{
|
||||
Name: "awssdk.client.LogResponse",
|
||||
Fn: logResponse,
|
||||
}
|
||||
|
||||
func logResponse(r *request.Request) {
|
||||
lw := &logWriter{r.Config.Logger, bytes.NewBuffer(nil)}
|
||||
r.HTTPResponse.Body = &teeReaderCloser{
|
||||
Reader: io.TeeReader(r.HTTPResponse.Body, lw),
|
||||
Source: r.HTTPResponse.Body,
|
||||
|
||||
if r.HTTPResponse == nil {
|
||||
lw.Logger.Log(fmt.Sprintf(logRespErrMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, "request's HTTPResponse is nil"))
|
||||
return
|
||||
}
|
||||
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
if logBody {
|
||||
r.HTTPResponse.Body = &teeReaderCloser{
|
||||
Reader: io.TeeReader(r.HTTPResponse.Body, lw),
|
||||
Source: r.HTTPResponse.Body,
|
||||
}
|
||||
}
|
||||
|
||||
handlerFn := func(req *request.Request) {
|
||||
body, err := httputil.DumpResponse(req.HTTPResponse, false)
|
||||
b, err := httputil.DumpResponse(req.HTTPResponse, false)
|
||||
if err != nil {
|
||||
lw.Logger.Log(fmt.Sprintf(logRespErrMsg, req.ClientInfo.ServiceName, req.Operation.Name, err))
|
||||
lw.Logger.Log(fmt.Sprintf(logRespErrMsg,
|
||||
req.ClientInfo.ServiceName, req.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(lw.buf)
|
||||
if err != nil {
|
||||
lw.Logger.Log(fmt.Sprintf(logRespErrMsg, req.ClientInfo.ServiceName, req.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
lw.Logger.Log(fmt.Sprintf(logRespMsg, req.ClientInfo.ServiceName, req.Operation.Name, string(body)))
|
||||
if req.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) {
|
||||
lw.Logger.Log(fmt.Sprintf(logRespMsg,
|
||||
req.ClientInfo.ServiceName, req.Operation.Name, string(b)))
|
||||
|
||||
if logBody {
|
||||
b, err := ioutil.ReadAll(lw.buf)
|
||||
if err != nil {
|
||||
lw.Logger.Log(fmt.Sprintf(logRespErrMsg,
|
||||
req.ClientInfo.ServiceName, req.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
lw.Logger.Log(string(b))
|
||||
}
|
||||
}
|
||||
|
@ -106,3 +164,27 @@ func logResponse(r *request.Request) {
|
|||
Name: handlerName, Fn: handlerFn,
|
||||
})
|
||||
}
|
||||
|
||||
// LogHTTPResponseHeaderHandler is a SDK request handler to log the HTTP
|
||||
// response received from a service. Will only log the HTTP response's headers.
|
||||
// The response payload will not be read.
|
||||
var LogHTTPResponseHeaderHandler = request.NamedHandler{
|
||||
Name: "awssdk.client.LogResponseHeader",
|
||||
Fn: logResponseHeader,
|
||||
}
|
||||
|
||||
func logResponseHeader(r *request.Request) {
|
||||
if r.Config.Logger == nil {
|
||||
return
|
||||
}
|
||||
|
||||
b, err := httputil.DumpResponse(r.HTTPResponse, false)
|
||||
if err != nil {
|
||||
r.Config.Logger.Log(fmt.Sprintf(logRespErrMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logRespMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, string(b)))
|
||||
}
|
||||
|
|
57
vendor/github.com/aws/aws-sdk-go/aws/client/logger_test.go
generated
vendored
57
vendor/github.com/aws/aws-sdk-go/aws/client/logger_test.go
generated
vendored
|
@ -1,57 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type mockCloser struct {
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (closer *mockCloser) Read(b []byte) (int, error) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
func (closer *mockCloser) Close() error {
|
||||
closer.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestTeeReaderCloser(t *testing.T) {
|
||||
expected := "FOO"
|
||||
buf := bytes.NewBuffer([]byte(expected))
|
||||
lw := bytes.NewBuffer(nil)
|
||||
c := &mockCloser{}
|
||||
closer := teeReaderCloser{
|
||||
io.TeeReader(buf, lw),
|
||||
c,
|
||||
}
|
||||
|
||||
b := make([]byte, len(expected))
|
||||
_, err := closer.Read(b)
|
||||
closer.Close()
|
||||
|
||||
if expected != lw.String() {
|
||||
t.Errorf("Expected %q, but received %q", expected, lw.String())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected 'nil', but received %v", err)
|
||||
}
|
||||
|
||||
if !c.closed {
|
||||
t.Error("Expected 'true', but received 'false'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogWriter(t *testing.T) {
|
||||
expected := "FOO"
|
||||
lw := &logWriter{nil, bytes.NewBuffer(nil)}
|
||||
lw.Write([]byte(expected))
|
||||
|
||||
if expected != lw.buf.String() {
|
||||
t.Errorf("Expected %q, but received %q", expected, lw.buf.String())
|
||||
}
|
||||
}
|
1
vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
1
vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
|
@ -3,6 +3,7 @@ package metadata
|
|||
// ClientInfo wraps immutable data from the client.Client structure.
|
||||
type ClientInfo struct {
|
||||
ServiceName string
|
||||
ServiceID string
|
||||
APIVersion string
|
||||
Endpoint string
|
||||
SigningName string
|
||||
|
|
84
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
84
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
|
@ -18,7 +18,7 @@ const UseServiceDefaultRetries = -1
|
|||
type RequestRetryer interface{}
|
||||
|
||||
// A Config provides service configuration for service clients. By default,
|
||||
// all clients will use the defaults.DefaultConfig tructure.
|
||||
// all clients will use the defaults.DefaultConfig structure.
|
||||
//
|
||||
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||
// // service clients.
|
||||
|
@ -45,8 +45,8 @@ type Config struct {
|
|||
// that overrides the default generated endpoint for a client. Set this
|
||||
// to `""` to use the default generated endpoint.
|
||||
//
|
||||
// @note You must still provide a `Region` value when specifying an
|
||||
// endpoint for a client.
|
||||
// Note: You must still provide a `Region` value when specifying an
|
||||
// endpoint for a client.
|
||||
Endpoint *string
|
||||
|
||||
// The resolver to use for looking up endpoints for AWS service clients
|
||||
|
@ -65,8 +65,8 @@ type Config struct {
|
|||
// noted. A full list of regions is found in the "Regions and Endpoints"
|
||||
// document.
|
||||
//
|
||||
// @see http://docs.aws.amazon.com/general/latest/gr/rande.html
|
||||
// AWS Regions and Endpoints
|
||||
// See http://docs.aws.amazon.com/general/latest/gr/rande.html for AWS
|
||||
// Regions and Endpoints.
|
||||
Region *string
|
||||
|
||||
// Set this to `true` to disable SSL when sending requests. Defaults
|
||||
|
@ -120,9 +120,10 @@ type Config struct {
|
|||
// will use virtual hosted bucket addressing when possible
|
||||
// (`http://BUCKET.s3.amazonaws.com/KEY`).
|
||||
//
|
||||
// @note This configuration option is specific to the Amazon S3 service.
|
||||
// @see http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html
|
||||
// Amazon S3: Virtual Hosting of Buckets
|
||||
// Note: This configuration option is specific to the Amazon S3 service.
|
||||
//
|
||||
// See http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html
|
||||
// for Amazon S3: Virtual Hosting of Buckets
|
||||
S3ForcePathStyle *bool
|
||||
|
||||
// Set this to `true` to disable the SDK adding the `Expect: 100-Continue`
|
||||
|
@ -151,6 +152,15 @@ type Config struct {
|
|||
// with accelerate.
|
||||
S3UseAccelerate *bool
|
||||
|
||||
// S3DisableContentMD5Validation config option is temporarily disabled,
|
||||
// For S3 GetObject API calls, #1837.
|
||||
//
|
||||
// Set this to `true` to disable the S3 service client from automatically
|
||||
// adding the ContentMD5 to S3 Object Put and Upload API calls. This option
|
||||
// will also disable the SDK from performing object ContentMD5 validation
|
||||
// on GetObject API calls.
|
||||
S3DisableContentMD5Validation *bool
|
||||
|
||||
// Set this to `true` to disable the EC2Metadata client from overriding the
|
||||
// default http.Client's Timeout. This is helpful if you do not want the
|
||||
// EC2Metadata client to create a new http.Client. This options is only
|
||||
|
@ -168,7 +178,7 @@ type Config struct {
|
|||
//
|
||||
EC2MetadataDisableTimeoutOverride *bool
|
||||
|
||||
// Instructs the endpiont to be generated for a service client to
|
||||
// Instructs the endpoint to be generated for a service client to
|
||||
// be the dual stack endpoint. The dual stack endpoint will support
|
||||
// both IPv4 and IPv6 addressing.
|
||||
//
|
||||
|
@ -214,6 +224,28 @@ type Config struct {
|
|||
// Key: aws.String("//foo//bar//moo"),
|
||||
// })
|
||||
DisableRestProtocolURICleaning *bool
|
||||
|
||||
// EnableEndpointDiscovery will allow for endpoint discovery on operations that
|
||||
// have the definition in its model. By default, endpoint discovery is off.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.Must(session.NewSession(&aws.Config{
|
||||
// EnableEndpointDiscovery: aws.Bool(true),
|
||||
// }))
|
||||
//
|
||||
// svc := s3.New(sess)
|
||||
// out, err := svc.GetObject(&s3.GetObjectInput {
|
||||
// Bucket: aws.String("bucketname"),
|
||||
// Key: aws.String("/foo/bar/moo"),
|
||||
// })
|
||||
EnableEndpointDiscovery *bool
|
||||
|
||||
// DisableEndpointHostPrefix will disable the SDK's behavior of prefixing
|
||||
// request endpoint hosts with modeled information.
|
||||
//
|
||||
// Disabling this feature is useful when you want to use local endpoints
|
||||
// for testing that do not support the modeled host prefix pattern.
|
||||
DisableEndpointHostPrefix *bool
|
||||
}
|
||||
|
||||
// NewConfig returns a new Config pointer that can be chained with builder
|
||||
|
@ -336,6 +368,15 @@ func (c *Config) WithS3Disable100Continue(disable bool) *Config {
|
|||
func (c *Config) WithS3UseAccelerate(enable bool) *Config {
|
||||
c.S3UseAccelerate = &enable
|
||||
return c
|
||||
|
||||
}
|
||||
|
||||
// WithS3DisableContentMD5Validation sets a config
|
||||
// S3DisableContentMD5Validation value returning a Config pointer for chaining.
|
||||
func (c *Config) WithS3DisableContentMD5Validation(enable bool) *Config {
|
||||
c.S3DisableContentMD5Validation = &enable
|
||||
return c
|
||||
|
||||
}
|
||||
|
||||
// WithUseDualStack sets a config UseDualStack value returning a Config
|
||||
|
@ -359,6 +400,19 @@ func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config {
|
|||
return c
|
||||
}
|
||||
|
||||
// WithEndpointDiscovery will set whether or not to use endpoint discovery.
|
||||
func (c *Config) WithEndpointDiscovery(t bool) *Config {
|
||||
c.EnableEndpointDiscovery = &t
|
||||
return c
|
||||
}
|
||||
|
||||
// WithDisableEndpointHostPrefix will set whether or not to use modeled host prefix
|
||||
// when making requests.
|
||||
func (c *Config) WithDisableEndpointHostPrefix(t bool) *Config {
|
||||
c.DisableEndpointHostPrefix = &t
|
||||
return c
|
||||
}
|
||||
|
||||
// MergeIn merges the passed in configs into the existing config object.
|
||||
func (c *Config) MergeIn(cfgs ...*Config) {
|
||||
for _, other := range cfgs {
|
||||
|
@ -435,6 +489,10 @@ func mergeInConfig(dst *Config, other *Config) {
|
|||
dst.S3UseAccelerate = other.S3UseAccelerate
|
||||
}
|
||||
|
||||
if other.S3DisableContentMD5Validation != nil {
|
||||
dst.S3DisableContentMD5Validation = other.S3DisableContentMD5Validation
|
||||
}
|
||||
|
||||
if other.UseDualStack != nil {
|
||||
dst.UseDualStack = other.UseDualStack
|
||||
}
|
||||
|
@ -454,6 +512,14 @@ func mergeInConfig(dst *Config, other *Config) {
|
|||
if other.EnforceShouldRetryCheck != nil {
|
||||
dst.EnforceShouldRetryCheck = other.EnforceShouldRetryCheck
|
||||
}
|
||||
|
||||
if other.EnableEndpointDiscovery != nil {
|
||||
dst.EnableEndpointDiscovery = other.EnableEndpointDiscovery
|
||||
}
|
||||
|
||||
if other.DisableEndpointHostPrefix != nil {
|
||||
dst.DisableEndpointHostPrefix = other.DisableEndpointHostPrefix
|
||||
}
|
||||
}
|
||||
|
||||
// Copy will return a shallow copy of the Config object. If any additional
|
||||
|
|
86
vendor/github.com/aws/aws-sdk-go/aws/config_test.go
generated
vendored
86
vendor/github.com/aws/aws-sdk-go/aws/config_test.go
generated
vendored
|
@ -1,86 +0,0 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
)
|
||||
|
||||
var testCredentials = credentials.NewStaticCredentials("AKID", "SECRET", "SESSION")
|
||||
|
||||
var copyTestConfig = Config{
|
||||
Credentials: testCredentials,
|
||||
Endpoint: String("CopyTestEndpoint"),
|
||||
Region: String("COPY_TEST_AWS_REGION"),
|
||||
DisableSSL: Bool(true),
|
||||
HTTPClient: http.DefaultClient,
|
||||
LogLevel: LogLevel(LogDebug),
|
||||
Logger: NewDefaultLogger(),
|
||||
MaxRetries: Int(3),
|
||||
DisableParamValidation: Bool(true),
|
||||
DisableComputeChecksums: Bool(true),
|
||||
S3ForcePathStyle: Bool(true),
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
want := copyTestConfig
|
||||
got := copyTestConfig.Copy()
|
||||
if !reflect.DeepEqual(*got, want) {
|
||||
t.Errorf("Copy() = %+v", got)
|
||||
t.Errorf(" want %+v", want)
|
||||
}
|
||||
|
||||
got.Region = String("other")
|
||||
if got.Region == want.Region {
|
||||
t.Errorf("Expect setting copy values not not reflect in source")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyReturnsNewInstance(t *testing.T) {
|
||||
want := copyTestConfig
|
||||
got := copyTestConfig.Copy()
|
||||
if got == &want {
|
||||
t.Errorf("Copy() = %p; want different instance as source %p", got, &want)
|
||||
}
|
||||
}
|
||||
|
||||
var mergeTestZeroValueConfig = Config{}
|
||||
|
||||
var mergeTestConfig = Config{
|
||||
Credentials: testCredentials,
|
||||
Endpoint: String("MergeTestEndpoint"),
|
||||
Region: String("MERGE_TEST_AWS_REGION"),
|
||||
DisableSSL: Bool(true),
|
||||
HTTPClient: http.DefaultClient,
|
||||
LogLevel: LogLevel(LogDebug),
|
||||
Logger: NewDefaultLogger(),
|
||||
MaxRetries: Int(10),
|
||||
DisableParamValidation: Bool(true),
|
||||
DisableComputeChecksums: Bool(true),
|
||||
S3ForcePathStyle: Bool(true),
|
||||
}
|
||||
|
||||
var mergeTests = []struct {
|
||||
cfg *Config
|
||||
in *Config
|
||||
want *Config
|
||||
}{
|
||||
{&Config{}, nil, &Config{}},
|
||||
{&Config{}, &mergeTestZeroValueConfig, &Config{}},
|
||||
{&Config{}, &mergeTestConfig, &mergeTestConfig},
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
for i, tt := range mergeTests {
|
||||
got := tt.cfg.Copy()
|
||||
got.MergeIn(tt.in)
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Config %d %+v", i, tt.cfg)
|
||||
t.Errorf(" Merge(%+v)", tt.in)
|
||||
t.Errorf(" got %+v", got)
|
||||
t.Errorf(" want %+v", tt.want)
|
||||
}
|
||||
}
|
||||
}
|
71
vendor/github.com/aws/aws-sdk-go/aws/context.go
generated
vendored
71
vendor/github.com/aws/aws-sdk-go/aws/context.go
generated
vendored
|
@ -1,71 +0,0 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Context is an copy of the Go v1.7 stdlib's context.Context interface.
|
||||
// It is represented as a SDK interface to enable you to use the "WithContext"
|
||||
// API methods with Go v1.6 and a Context type such as golang.org/x/net/context.
|
||||
//
|
||||
// See https://golang.org/pkg/context on how to use contexts.
|
||||
type Context interface {
|
||||
// Deadline returns the time when work done on behalf of this context
|
||||
// should be canceled. Deadline returns ok==false when no deadline is
|
||||
// set. Successive calls to Deadline return the same results.
|
||||
Deadline() (deadline time.Time, ok bool)
|
||||
|
||||
// Done returns a channel that's closed when work done on behalf of this
|
||||
// context should be canceled. Done may return nil if this context can
|
||||
// never be canceled. Successive calls to Done return the same value.
|
||||
Done() <-chan struct{}
|
||||
|
||||
// Err returns a non-nil error value after Done is closed. Err returns
|
||||
// Canceled if the context was canceled or DeadlineExceeded if the
|
||||
// context's deadline passed. No other values for Err are defined.
|
||||
// After Done is closed, successive calls to Err return the same value.
|
||||
Err() error
|
||||
|
||||
// Value returns the value associated with this context for key, or nil
|
||||
// if no value is associated with key. Successive calls to Value with
|
||||
// the same key returns the same result.
|
||||
//
|
||||
// Use context values only for request-scoped data that transits
|
||||
// processes and API boundaries, not for passing optional parameters to
|
||||
// functions.
|
||||
Value(key interface{}) interface{}
|
||||
}
|
||||
|
||||
// BackgroundContext returns a context that will never be canceled, has no
|
||||
// values, and no deadline. This context is used by the SDK to provide
|
||||
// backwards compatibility with non-context API operations and functionality.
|
||||
//
|
||||
// Go 1.6 and before:
|
||||
// This context function is equivalent to context.Background in the Go stdlib.
|
||||
//
|
||||
// Go 1.7 and later:
|
||||
// The context returned will be the value returned by context.Background()
|
||||
//
|
||||
// See https://golang.org/pkg/context for more information on Contexts.
|
||||
func BackgroundContext() Context {
|
||||
return backgroundCtx
|
||||
}
|
||||
|
||||
// SleepWithContext will wait for the timer duration to expire, or the context
|
||||
// is canceled. Which ever happens first. If the context is canceled the Context's
|
||||
// error will be returned.
|
||||
//
|
||||
// Expects Context to always return a non-nil error if the Done channel is closed.
|
||||
func SleepWithContext(ctx Context, dur time.Duration) error {
|
||||
t := time.NewTimer(dur)
|
||||
defer t.Stop()
|
||||
|
||||
select {
|
||||
case <-t.C:
|
||||
break
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
37
vendor/github.com/aws/aws-sdk-go/aws/context_1_5.go
generated
vendored
Normal file
37
vendor/github.com/aws/aws-sdk-go/aws/context_1_5.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
// +build !go1.9
|
||||
|
||||
package aws
|
||||
|
||||
import "time"
|
||||
|
||||
// Context is an copy of the Go v1.7 stdlib's context.Context interface.
|
||||
// It is represented as a SDK interface to enable you to use the "WithContext"
|
||||
// API methods with Go v1.6 and a Context type such as golang.org/x/net/context.
|
||||
//
|
||||
// See https://golang.org/pkg/context on how to use contexts.
|
||||
type Context interface {
|
||||
// Deadline returns the time when work done on behalf of this context
|
||||
// should be canceled. Deadline returns ok==false when no deadline is
|
||||
// set. Successive calls to Deadline return the same results.
|
||||
Deadline() (deadline time.Time, ok bool)
|
||||
|
||||
// Done returns a channel that's closed when work done on behalf of this
|
||||
// context should be canceled. Done may return nil if this context can
|
||||
// never be canceled. Successive calls to Done return the same value.
|
||||
Done() <-chan struct{}
|
||||
|
||||
// Err returns a non-nil error value after Done is closed. Err returns
|
||||
// Canceled if the context was canceled or DeadlineExceeded if the
|
||||
// context's deadline passed. No other values for Err are defined.
|
||||
// After Done is closed, successive calls to Err return the same value.
|
||||
Err() error
|
||||
|
||||
// Value returns the value associated with this context for key, or nil
|
||||
// if no value is associated with key. Successive calls to Value with
|
||||
// the same key returns the same result.
|
||||
//
|
||||
// Use context values only for request-scoped data that transits
|
||||
// processes and API boundaries, not for passing optional parameters to
|
||||
// functions.
|
||||
Value(key interface{}) interface{}
|
||||
}
|
41
vendor/github.com/aws/aws-sdk-go/aws/context_1_6.go
generated
vendored
41
vendor/github.com/aws/aws-sdk-go/aws/context_1_6.go
generated
vendored
|
@ -1,41 +0,0 @@
|
|||
// +build !go1.7
|
||||
|
||||
package aws
|
||||
|
||||
import "time"
|
||||
|
||||
// An emptyCtx is a copy of the Go 1.7 context.emptyCtx type. This is copied to
|
||||
// provide a 1.6 and 1.5 safe version of context that is compatible with Go
|
||||
// 1.7's Context.
|
||||
//
|
||||
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||
// struct{}, since vars of this type must have distinct addresses.
|
||||
type emptyCtx int
|
||||
|
||||
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func (*emptyCtx) Done() <-chan struct{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*emptyCtx) Err() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*emptyCtx) Value(key interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *emptyCtx) String() string {
|
||||
switch e {
|
||||
case backgroundCtx:
|
||||
return "aws.BackgroundContext"
|
||||
}
|
||||
return "unknown empty Context"
|
||||
}
|
||||
|
||||
var (
|
||||
backgroundCtx = new(emptyCtx)
|
||||
)
|
9
vendor/github.com/aws/aws-sdk-go/aws/context_1_7.go
generated
vendored
9
vendor/github.com/aws/aws-sdk-go/aws/context_1_7.go
generated
vendored
|
@ -1,9 +0,0 @@
|
|||
// +build go1.7
|
||||
|
||||
package aws
|
||||
|
||||
import "context"
|
||||
|
||||
var (
|
||||
backgroundCtx = context.Background()
|
||||
)
|
11
vendor/github.com/aws/aws-sdk-go/aws/context_1_9.go
generated
vendored
Normal file
11
vendor/github.com/aws/aws-sdk-go/aws/context_1_9.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
// +build go1.9
|
||||
|
||||
package aws
|
||||
|
||||
import "context"
|
||||
|
||||
// Context is an alias of the Go stdlib's context.Context interface.
|
||||
// It can be used within the SDK's API operation "WithContext" methods.
|
||||
//
|
||||
// See https://golang.org/pkg/context on how to use contexts.
|
||||
type Context = context.Context
|
56
vendor/github.com/aws/aws-sdk-go/aws/context_background_1_5.go
generated
vendored
Normal file
56
vendor/github.com/aws/aws-sdk-go/aws/context_background_1_5.go
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
// +build !go1.7
|
||||
|
||||
package aws
|
||||
|
||||
import "time"
|
||||
|
||||
// An emptyCtx is a copy of the Go 1.7 context.emptyCtx type. This is copied to
|
||||
// provide a 1.6 and 1.5 safe version of context that is compatible with Go
|
||||
// 1.7's Context.
|
||||
//
|
||||
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||
// struct{}, since vars of this type must have distinct addresses.
|
||||
type emptyCtx int
|
||||
|
||||
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func (*emptyCtx) Done() <-chan struct{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*emptyCtx) Err() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*emptyCtx) Value(key interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *emptyCtx) String() string {
|
||||
switch e {
|
||||
case backgroundCtx:
|
||||
return "aws.BackgroundContext"
|
||||
}
|
||||
return "unknown empty Context"
|
||||
}
|
||||
|
||||
var (
|
||||
backgroundCtx = new(emptyCtx)
|
||||
)
|
||||
|
||||
// BackgroundContext returns a context that will never be canceled, has no
|
||||
// values, and no deadline. This context is used by the SDK to provide
|
||||
// backwards compatibility with non-context API operations and functionality.
|
||||
//
|
||||
// Go 1.6 and before:
|
||||
// This context function is equivalent to context.Background in the Go stdlib.
|
||||
//
|
||||
// Go 1.7 and later:
|
||||
// The context returned will be the value returned by context.Background()
|
||||
//
|
||||
// See https://golang.org/pkg/context for more information on Contexts.
|
||||
func BackgroundContext() Context {
|
||||
return backgroundCtx
|
||||
}
|
20
vendor/github.com/aws/aws-sdk-go/aws/context_background_1_7.go
generated
vendored
Normal file
20
vendor/github.com/aws/aws-sdk-go/aws/context_background_1_7.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
// +build go1.7
|
||||
|
||||
package aws
|
||||
|
||||
import "context"
|
||||
|
||||
// BackgroundContext returns a context that will never be canceled, has no
|
||||
// values, and no deadline. This context is used by the SDK to provide
|
||||
// backwards compatibility with non-context API operations and functionality.
|
||||
//
|
||||
// Go 1.6 and before:
|
||||
// This context function is equivalent to context.Background in the Go stdlib.
|
||||
//
|
||||
// Go 1.7 and later:
|
||||
// The context returned will be the value returned by context.Background()
|
||||
//
|
||||
// See https://golang.org/pkg/context for more information on Contexts.
|
||||
func BackgroundContext() Context {
|
||||
return context.Background()
|
||||
}
|
24
vendor/github.com/aws/aws-sdk-go/aws/context_sleep.go
generated
vendored
Normal file
24
vendor/github.com/aws/aws-sdk-go/aws/context_sleep.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// SleepWithContext will wait for the timer duration to expire, or the context
|
||||
// is canceled. Which ever happens first. If the context is canceled the Context's
|
||||
// error will be returned.
|
||||
//
|
||||
// Expects Context to always return a non-nil error if the Done channel is closed.
|
||||
func SleepWithContext(ctx Context, dur time.Duration) error {
|
||||
t := time.NewTimer(dur)
|
||||
defer t.Stop()
|
||||
|
||||
select {
|
||||
case <-t.C:
|
||||
break
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
37
vendor/github.com/aws/aws-sdk-go/aws/context_test.go
generated
vendored
37
vendor/github.com/aws/aws-sdk-go/aws/context_test.go
generated
vendored
|
@ -1,37 +0,0 @@
|
|||
package aws_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
)
|
||||
|
||||
func TestSleepWithContext(t *testing.T) {
|
||||
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
|
||||
|
||||
err := aws.SleepWithContext(ctx, 1*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Errorf("expect context to not be canceled, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSleepWithContext_Canceled(t *testing.T) {
|
||||
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
|
||||
|
||||
expectErr := fmt.Errorf("context canceled")
|
||||
|
||||
ctx.Error = expectErr
|
||||
close(ctx.DoneCh)
|
||||
|
||||
err := aws.SleepWithContext(ctx, 1*time.Millisecond)
|
||||
if err == nil {
|
||||
t.Fatalf("expect error, did not get one")
|
||||
}
|
||||
|
||||
if e, a := expectErr, err; e != a {
|
||||
t.Errorf("expect %v error, got %v", e, a)
|
||||
}
|
||||
}
|
641
vendor/github.com/aws/aws-sdk-go/aws/convert_types_test.go
generated
vendored
641
vendor/github.com/aws/aws-sdk-go/aws/convert_types_test.go
generated
vendored
|
@ -1,641 +0,0 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var testCasesStringSlice = [][]string{
|
||||
{"a", "b", "c", "d", "e"},
|
||||
{"a", "b", "", "", "e"},
|
||||
}
|
||||
|
||||
func TestStringSlice(t *testing.T) {
|
||||
for idx, in := range testCasesStringSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := StringSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := StringValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesStringValueSlice = [][]*string{
|
||||
{String("a"), String("b"), nil, String("c")},
|
||||
}
|
||||
|
||||
func TestStringValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesStringValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := StringValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if out[i] != "" {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := StringSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if *(out2[i]) != "" {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *in[i], *out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesStringMap = []map[string]string{
|
||||
{"a": "1", "b": "2", "c": "3"},
|
||||
}
|
||||
|
||||
func TestStringMap(t *testing.T) {
|
||||
for idx, in := range testCasesStringMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := StringMap(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := StringValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesBoolSlice = [][]bool{
|
||||
{true, true, false, false},
|
||||
}
|
||||
|
||||
func TestBoolSlice(t *testing.T) {
|
||||
for idx, in := range testCasesBoolSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := BoolSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := BoolValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesBoolValueSlice = [][]*bool{}
|
||||
|
||||
func TestBoolValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesBoolValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := BoolValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if out[i] {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := BoolSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if *(out2[i]) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := in[i], out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesBoolMap = []map[string]bool{
|
||||
{"a": true, "b": false, "c": true},
|
||||
}
|
||||
|
||||
func TestBoolMap(t *testing.T) {
|
||||
for idx, in := range testCasesBoolMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := BoolMap(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := BoolValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesIntSlice = [][]int{
|
||||
{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
func TestIntSlice(t *testing.T) {
|
||||
for idx, in := range testCasesIntSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := IntSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := IntValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesIntValueSlice = [][]*int{}
|
||||
|
||||
func TestIntValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesIntValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := IntValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if out[i] != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := IntSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if *(out2[i]) != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := in[i], out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesIntMap = []map[string]int{
|
||||
{"a": 3, "b": 2, "c": 1},
|
||||
}
|
||||
|
||||
func TestIntMap(t *testing.T) {
|
||||
for idx, in := range testCasesIntMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := IntMap(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := IntValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesInt64Slice = [][]int64{
|
||||
{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
func TestInt64Slice(t *testing.T) {
|
||||
for idx, in := range testCasesInt64Slice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Int64Slice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Int64ValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesInt64ValueSlice = [][]*int64{}
|
||||
|
||||
func TestInt64ValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesInt64ValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Int64ValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if out[i] != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Int64Slice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if *(out2[i]) != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := in[i], out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesInt64Map = []map[string]int64{
|
||||
{"a": 3, "b": 2, "c": 1},
|
||||
}
|
||||
|
||||
func TestInt64Map(t *testing.T) {
|
||||
for idx, in := range testCasesInt64Map {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Int64Map(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Int64ValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesFloat64Slice = [][]float64{
|
||||
{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
func TestFloat64Slice(t *testing.T) {
|
||||
for idx, in := range testCasesFloat64Slice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Float64Slice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Float64ValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesFloat64ValueSlice = [][]*float64{}
|
||||
|
||||
func TestFloat64ValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesFloat64ValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Float64ValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if out[i] != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Float64Slice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if *(out2[i]) != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := in[i], out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesFloat64Map = []map[string]float64{
|
||||
{"a": 3, "b": 2, "c": 1},
|
||||
}
|
||||
|
||||
func TestFloat64Map(t *testing.T) {
|
||||
for idx, in := range testCasesFloat64Map {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Float64Map(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Float64ValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesTimeSlice = [][]time.Time{
|
||||
{time.Now(), time.Now().AddDate(100, 0, 0)},
|
||||
}
|
||||
|
||||
func TestTimeSlice(t *testing.T) {
|
||||
for idx, in := range testCasesTimeSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := TimeSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := TimeValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesTimeValueSlice = [][]*time.Time{}
|
||||
|
||||
func TestTimeValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesTimeValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := TimeValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if !out[i].IsZero() {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := TimeSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if !(*(out2[i])).IsZero() {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := in[i], out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesTimeMap = []map[string]time.Time{
|
||||
{"a": time.Now().AddDate(-100, 0, 0), "b": time.Now()},
|
||||
}
|
||||
|
||||
func TestTimeMap(t *testing.T) {
|
||||
for idx, in := range testCasesTimeMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := TimeMap(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := TimeValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TimeValueTestCase struct {
|
||||
in int64
|
||||
outSecs time.Time
|
||||
outMillis time.Time
|
||||
}
|
||||
|
||||
var testCasesTimeValue = []TimeValueTestCase{
|
||||
{
|
||||
in: int64(1501558289000),
|
||||
outSecs: time.Unix(1501558289, 0),
|
||||
outMillis: time.Unix(1501558289, 0),
|
||||
},
|
||||
{
|
||||
in: int64(1501558289001),
|
||||
outSecs: time.Unix(1501558289, 0),
|
||||
outMillis: time.Unix(1501558289, 1*1000000),
|
||||
},
|
||||
}
|
||||
|
||||
func TestSecondsTimeValue(t *testing.T) {
|
||||
for idx, testCase := range testCasesTimeValue {
|
||||
out := SecondsTimeValue(&testCase.in)
|
||||
if e, a := testCase.outSecs, out; e != a {
|
||||
t.Errorf("Unexpected value for time value at %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMillisecondsTimeValue(t *testing.T) {
|
||||
for idx, testCase := range testCasesTimeValue {
|
||||
out := MillisecondsTimeValue(&testCase.in)
|
||||
if e, a := testCase.outMillis, out; e != a {
|
||||
t.Errorf("Unexpected value for time value at %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
32
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
generated
vendored
32
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
generated
vendored
|
@ -3,12 +3,10 @@ package corehandlers
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -36,18 +34,13 @@ var BuildContentLengthHandler = request.NamedHandler{Name: "core.BuildContentLen
|
|||
if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" {
|
||||
length, _ = strconv.ParseInt(slength, 10, 64)
|
||||
} else {
|
||||
switch body := r.Body.(type) {
|
||||
case nil:
|
||||
length = 0
|
||||
case lener:
|
||||
length = int64(body.Len())
|
||||
case io.Seeker:
|
||||
r.BodyStart, _ = body.Seek(0, 1)
|
||||
end, _ := body.Seek(0, 2)
|
||||
body.Seek(r.BodyStart, 0) // make sure to seek back to original location
|
||||
length = end - r.BodyStart
|
||||
default:
|
||||
panic("Cannot get length of body, must provide `ContentLength`")
|
||||
if r.Body != nil {
|
||||
var err error
|
||||
length, err = aws.SeekerLen(r.Body)
|
||||
if err != nil {
|
||||
r.Error = awserr.New(request.ErrCodeSerialization, "failed to get request body's length", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,13 +53,6 @@ var BuildContentLengthHandler = request.NamedHandler{Name: "core.BuildContentLen
|
|||
}
|
||||
}}
|
||||
|
||||
// SDKVersionUserAgentHandler is a request handler for adding the SDK Version to the user agent.
|
||||
var SDKVersionUserAgentHandler = request.NamedHandler{
|
||||
Name: "core.SDKVersionUserAgentHandler",
|
||||
Fn: request.MakeAddToUserAgentHandler(aws.SDKName, aws.SDKVersion,
|
||||
runtime.Version(), runtime.GOOS, runtime.GOARCH),
|
||||
}
|
||||
|
||||
var reStatusCode = regexp.MustCompile(`^(\d{3})`)
|
||||
|
||||
// ValidateReqSigHandler is a request handler to ensure that the request's
|
||||
|
@ -86,9 +72,9 @@ var ValidateReqSigHandler = request.NamedHandler{
|
|||
signedTime = r.LastSignedAt
|
||||
}
|
||||
|
||||
// 10 minutes to allow for some clock skew/delays in transmission.
|
||||
// 5 minutes to allow for some clock skew/delays in transmission.
|
||||
// Would be improved with aws/aws-sdk-go#423
|
||||
if signedTime.Add(10 * time.Minute).After(time.Now()) {
|
||||
if signedTime.Add(5 * time.Minute).After(time.Now()) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
64
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_1_8_test.go
generated
vendored
64
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_1_8_test.go
generated
vendored
|
@ -1,64 +0,0 @@
|
|||
// +build go1.8
|
||||
|
||||
package corehandlers_test
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
func TestSendHandler_HEADNoBody(t *testing.T) {
|
||||
TLSBundleCertFile, TLSBundleKeyFile, TLSBundleCAFile, err := awstesting.CreateTLSBundleFiles()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer awstesting.CleanupTLSBundleFiles(TLSBundleCertFile, TLSBundleKeyFile, TLSBundleCAFile)
|
||||
|
||||
endpoint, err := awstesting.CreateTLSServer(TLSBundleCertFile, TLSBundleKeyFile, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("expect no error, got %v", err)
|
||||
}
|
||||
|
||||
transport := http.DefaultTransport.(*http.Transport)
|
||||
// test server's certificate is self-signed certificate
|
||||
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
http2.ConfigureTransport(transport)
|
||||
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Config: aws.Config{
|
||||
HTTPClient: &http.Client{},
|
||||
Endpoint: aws.String(endpoint),
|
||||
Region: aws.String("mock-region"),
|
||||
Credentials: credentials.AnonymousCredentials,
|
||||
S3ForcePathStyle: aws.Bool(true),
|
||||
},
|
||||
})
|
||||
|
||||
svc := s3.New(sess)
|
||||
|
||||
req, _ := svc.HeadObjectRequest(&s3.HeadObjectInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Key: aws.String("keyname"),
|
||||
})
|
||||
|
||||
if e, a := request.NoBody, req.HTTPRequest.Body; e != a {
|
||||
t.Fatalf("expect %T request body, got %T", e, a)
|
||||
}
|
||||
|
||||
err = req.Send()
|
||||
if err != nil {
|
||||
t.Fatalf("expect no error, got %v", err)
|
||||
}
|
||||
if e, a := http.StatusOK, req.HTTPResponse.StatusCode; e != a {
|
||||
t.Errorf("expect %d status code, got %d", e, a)
|
||||
}
|
||||
}
|
398
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_test.go
generated
vendored
398
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_test.go
generated
vendored
|
@ -1,398 +0,0 @@
|
|||
package corehandlers_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
func TestValidateEndpointHandler(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
svc := awstesting.NewClient(aws.NewConfig().WithRegion("us-west-2"))
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
|
||||
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
err := req.Build()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateEndpointHandlerErrorRegion(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
svc := awstesting.NewClient()
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
|
||||
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
err := req.Build()
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("expect error, got none")
|
||||
}
|
||||
if e, a := aws.ErrMissingRegion, err; e != a {
|
||||
t.Errorf("expect %v to be %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
type mockCredsProvider struct {
|
||||
expired bool
|
||||
retrieveCalled bool
|
||||
}
|
||||
|
||||
func (m *mockCredsProvider) Retrieve() (credentials.Value, error) {
|
||||
m.retrieveCalled = true
|
||||
return credentials.Value{ProviderName: "mockCredsProvider"}, nil
|
||||
}
|
||||
|
||||
func (m *mockCredsProvider) IsExpired() bool {
|
||||
return m.expired
|
||||
}
|
||||
|
||||
func TestAfterRetryRefreshCreds(t *testing.T) {
|
||||
os.Clearenv()
|
||||
credProvider := &mockCredsProvider{}
|
||||
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
Credentials: credentials.NewCredentials(credProvider),
|
||||
MaxRetries: aws.Int(1),
|
||||
})
|
||||
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.ValidateResponse.PushBack(func(r *request.Request) {
|
||||
r.Error = awserr.New("UnknownError", "", nil)
|
||||
r.HTTPResponse = &http.Response{StatusCode: 400, Body: ioutil.NopCloser(bytes.NewBuffer([]byte{}))}
|
||||
})
|
||||
svc.Handlers.UnmarshalError.PushBack(func(r *request.Request) {
|
||||
r.Error = awserr.New("ExpiredTokenException", "", nil)
|
||||
})
|
||||
svc.Handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
|
||||
if !svc.Config.Credentials.IsExpired() {
|
||||
t.Errorf("Expect to start out expired")
|
||||
}
|
||||
if credProvider.retrieveCalled {
|
||||
t.Errorf("expect not called")
|
||||
}
|
||||
|
||||
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
req.Send()
|
||||
|
||||
if !svc.Config.Credentials.IsExpired() {
|
||||
t.Errorf("Expect to start out expired")
|
||||
}
|
||||
if credProvider.retrieveCalled {
|
||||
t.Errorf("expect not called")
|
||||
}
|
||||
|
||||
_, err := svc.Config.Credentials.Get()
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
if !credProvider.retrieveCalled {
|
||||
t.Errorf("expect not called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAfterRetryWithContextCanceled(t *testing.T) {
|
||||
c := awstesting.NewClient()
|
||||
|
||||
req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
|
||||
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)}
|
||||
req.SetContext(ctx)
|
||||
|
||||
req.Error = fmt.Errorf("some error")
|
||||
req.Retryable = aws.Bool(true)
|
||||
req.HTTPResponse = &http.Response{
|
||||
StatusCode: 500,
|
||||
}
|
||||
|
||||
close(ctx.DoneCh)
|
||||
ctx.Error = fmt.Errorf("context canceled")
|
||||
|
||||
corehandlers.AfterRetryHandler.Fn(req)
|
||||
|
||||
if req.Error == nil {
|
||||
t.Fatalf("expect error but didn't receive one")
|
||||
}
|
||||
|
||||
aerr := req.Error.(awserr.Error)
|
||||
|
||||
if e, a := request.CanceledErrorCode, aerr.Code(); e != a {
|
||||
t.Errorf("expect %q, error code got %q", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAfterRetryWithContext(t *testing.T) {
|
||||
c := awstesting.NewClient()
|
||||
|
||||
req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
|
||||
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)}
|
||||
req.SetContext(ctx)
|
||||
|
||||
req.Error = fmt.Errorf("some error")
|
||||
req.Retryable = aws.Bool(true)
|
||||
req.HTTPResponse = &http.Response{
|
||||
StatusCode: 500,
|
||||
}
|
||||
|
||||
corehandlers.AfterRetryHandler.Fn(req)
|
||||
|
||||
if req.Error != nil {
|
||||
t.Fatalf("expect no error, got %v", req.Error)
|
||||
}
|
||||
if e, a := 1, req.RetryCount; e != a {
|
||||
t.Errorf("expect retry count to be %d, got %d", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithContextCanceled(t *testing.T) {
|
||||
c := awstesting.NewClient(&aws.Config{
|
||||
SleepDelay: func(dur time.Duration) {
|
||||
t.Errorf("SleepDelay should not be called")
|
||||
},
|
||||
})
|
||||
|
||||
req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
|
||||
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)}
|
||||
req.SetContext(ctx)
|
||||
|
||||
req.Error = fmt.Errorf("some error")
|
||||
req.Retryable = aws.Bool(true)
|
||||
req.HTTPResponse = &http.Response{
|
||||
StatusCode: 500,
|
||||
}
|
||||
|
||||
close(ctx.DoneCh)
|
||||
ctx.Error = fmt.Errorf("context canceled")
|
||||
|
||||
corehandlers.SendHandler.Fn(req)
|
||||
|
||||
if req.Error == nil {
|
||||
t.Fatalf("expect error but didn't receive one")
|
||||
}
|
||||
|
||||
aerr := req.Error.(awserr.Error)
|
||||
|
||||
if e, a := request.CanceledErrorCode, aerr.Code(); e != a {
|
||||
t.Errorf("expect %q, error code got %q", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
type testSendHandlerTransport struct{}
|
||||
|
||||
func (t *testSendHandlerTransport) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||
return nil, fmt.Errorf("mock error")
|
||||
}
|
||||
|
||||
func TestSendHandlerError(t *testing.T) {
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
HTTPClient: &http.Client{
|
||||
Transport: &testSendHandlerTransport{},
|
||||
},
|
||||
})
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
r := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
|
||||
r.Send()
|
||||
|
||||
if r.Error == nil {
|
||||
t.Errorf("expect error, got none")
|
||||
}
|
||||
if r.HTTPResponse == nil {
|
||||
t.Errorf("expect response, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithoutFollowRedirects(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/original":
|
||||
w.Header().Set("Location", "/redirected")
|
||||
w.WriteHeader(301)
|
||||
case "/redirected":
|
||||
t.Fatalf("expect not to redirect, but was")
|
||||
}
|
||||
}))
|
||||
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
DisableSSL: aws.Bool(true),
|
||||
Endpoint: aws.String(server.URL),
|
||||
})
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
|
||||
r := svc.NewRequest(&request.Operation{
|
||||
Name: "Operation",
|
||||
HTTPPath: "/original",
|
||||
}, nil, nil)
|
||||
r.DisableFollowRedirects = true
|
||||
|
||||
err := r.Send()
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
if e, a := 301, r.HTTPResponse.StatusCode; e != a {
|
||||
t.Errorf("expect %d status code, got %d", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateReqSigHandler(t *testing.T) {
|
||||
cases := []struct {
|
||||
Req *request.Request
|
||||
Resign bool
|
||||
}{
|
||||
{
|
||||
Req: &request.Request{
|
||||
Config: aws.Config{Credentials: credentials.AnonymousCredentials},
|
||||
Time: time.Now().Add(-15 * time.Minute),
|
||||
},
|
||||
Resign: false,
|
||||
},
|
||||
{
|
||||
Req: &request.Request{
|
||||
Time: time.Now().Add(-15 * time.Minute),
|
||||
},
|
||||
Resign: true,
|
||||
},
|
||||
{
|
||||
Req: &request.Request{
|
||||
Time: time.Now().Add(-1 * time.Minute),
|
||||
},
|
||||
Resign: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
resigned := false
|
||||
c.Req.Handlers.Sign.PushBack(func(r *request.Request) {
|
||||
resigned = true
|
||||
})
|
||||
|
||||
corehandlers.ValidateReqSigHandler.Fn(c.Req)
|
||||
|
||||
if c.Req.Error != nil {
|
||||
t.Errorf("expect no error, got %v", c.Req.Error)
|
||||
}
|
||||
if e, a := c.Resign, resigned; e != a {
|
||||
t.Errorf("%d, expect %v to be %v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setupContentLengthTestServer(t *testing.T, hasContentLength bool, contentLength int64) *httptest.Server {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, ok := r.Header["Content-Length"]
|
||||
if e, a := hasContentLength, ok; e != a {
|
||||
t.Errorf("expect %v to be %v", e, a)
|
||||
}
|
||||
if hasContentLength {
|
||||
if e, a := contentLength, r.ContentLength; e != a {
|
||||
t.Errorf("expect %v to be %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if hasContentLength {
|
||||
if e, a := "content-length", authHeader; !strings.Contains(a, e) {
|
||||
t.Errorf("expect %v to be in %v", e, a)
|
||||
}
|
||||
} else {
|
||||
if e, a := "content-length", authHeader; strings.Contains(a, e) {
|
||||
t.Errorf("expect %v to not be in %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
if e, a := contentLength, int64(len(b)); e != a {
|
||||
t.Errorf("expect %v to be %v", e, a)
|
||||
}
|
||||
}))
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func TestBuildContentLength_ZeroBody(t *testing.T) {
|
||||
server := setupContentLengthTestServer(t, false, 0)
|
||||
|
||||
svc := s3.New(unit.Session, &aws.Config{
|
||||
Endpoint: aws.String(server.URL),
|
||||
S3ForcePathStyle: aws.Bool(true),
|
||||
DisableSSL: aws.Bool(true),
|
||||
})
|
||||
_, err := svc.GetObject(&s3.GetObjectInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Key: aws.String("keyname"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildContentLength_NegativeBody(t *testing.T) {
|
||||
server := setupContentLengthTestServer(t, false, 0)
|
||||
|
||||
svc := s3.New(unit.Session, &aws.Config{
|
||||
Endpoint: aws.String(server.URL),
|
||||
S3ForcePathStyle: aws.Bool(true),
|
||||
DisableSSL: aws.Bool(true),
|
||||
})
|
||||
req, _ := svc.GetObjectRequest(&s3.GetObjectInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Key: aws.String("keyname"),
|
||||
})
|
||||
|
||||
req.HTTPRequest.Header.Set("Content-Length", "-1")
|
||||
|
||||
if req.Error != nil {
|
||||
t.Errorf("expect no error, got %v", req.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildContentLength_WithBody(t *testing.T) {
|
||||
server := setupContentLengthTestServer(t, true, 1024)
|
||||
|
||||
svc := s3.New(unit.Session, &aws.Config{
|
||||
Endpoint: aws.String(server.URL),
|
||||
S3ForcePathStyle: aws.Bool(true),
|
||||
DisableSSL: aws.Bool(true),
|
||||
})
|
||||
_, err := svc.PutObject(&s3.PutObjectInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Key: aws.String("keyname"),
|
||||
Body: bytes.NewReader(make([]byte, 1024)),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
}
|
286
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator_test.go
generated
vendored
286
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator_test.go
generated
vendored
|
@ -1,286 +0,0 @@
|
|||
package corehandlers_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"reflect"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/kinesis"
|
||||
)
|
||||
|
||||
var testSvc = func() *client.Client {
|
||||
s := &client.Client{
|
||||
Config: aws.Config{},
|
||||
ClientInfo: metadata.ClientInfo{
|
||||
ServiceName: "mock-service",
|
||||
APIVersion: "2015-01-01",
|
||||
},
|
||||
}
|
||||
return s
|
||||
}()
|
||||
|
||||
type StructShape struct {
|
||||
_ struct{} `type:"structure"`
|
||||
|
||||
RequiredList []*ConditionalStructShape `required:"true"`
|
||||
RequiredMap map[string]*ConditionalStructShape `required:"true"`
|
||||
RequiredBool *bool `required:"true"`
|
||||
OptionalStruct *ConditionalStructShape
|
||||
|
||||
hiddenParameter *string
|
||||
}
|
||||
|
||||
func (s *StructShape) Validate() error {
|
||||
invalidParams := request.ErrInvalidParams{Context: "StructShape"}
|
||||
if s.RequiredList == nil {
|
||||
invalidParams.Add(request.NewErrParamRequired("RequiredList"))
|
||||
}
|
||||
if s.RequiredMap == nil {
|
||||
invalidParams.Add(request.NewErrParamRequired("RequiredMap"))
|
||||
}
|
||||
if s.RequiredBool == nil {
|
||||
invalidParams.Add(request.NewErrParamRequired("RequiredBool"))
|
||||
}
|
||||
if s.RequiredList != nil {
|
||||
for i, v := range s.RequiredList {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
if err := v.Validate(); err != nil {
|
||||
invalidParams.AddNested(fmt.Sprintf("%s[%v]", "RequiredList", i), err.(request.ErrInvalidParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
if s.RequiredMap != nil {
|
||||
for i, v := range s.RequiredMap {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
if err := v.Validate(); err != nil {
|
||||
invalidParams.AddNested(fmt.Sprintf("%s[%v]", "RequiredMap", i), err.(request.ErrInvalidParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
if s.OptionalStruct != nil {
|
||||
if err := s.OptionalStruct.Validate(); err != nil {
|
||||
invalidParams.AddNested("OptionalStruct", err.(request.ErrInvalidParams))
|
||||
}
|
||||
}
|
||||
|
||||
if invalidParams.Len() > 0 {
|
||||
return invalidParams
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ConditionalStructShape struct {
|
||||
_ struct{} `type:"structure"`
|
||||
|
||||
Name *string `required:"true"`
|
||||
}
|
||||
|
||||
func (s *ConditionalStructShape) Validate() error {
|
||||
invalidParams := request.ErrInvalidParams{Context: "ConditionalStructShape"}
|
||||
if s.Name == nil {
|
||||
invalidParams.Add(request.NewErrParamRequired("Name"))
|
||||
}
|
||||
|
||||
if invalidParams.Len() > 0 {
|
||||
return invalidParams
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestNoErrors(t *testing.T) {
|
||||
input := &StructShape{
|
||||
RequiredList: []*ConditionalStructShape{},
|
||||
RequiredMap: map[string]*ConditionalStructShape{
|
||||
"key1": {Name: aws.String("Name")},
|
||||
"key2": {Name: aws.String("Name")},
|
||||
},
|
||||
RequiredBool: aws.Bool(true),
|
||||
OptionalStruct: &ConditionalStructShape{Name: aws.String("Name")},
|
||||
}
|
||||
|
||||
req := testSvc.NewRequest(&request.Operation{}, input, nil)
|
||||
corehandlers.ValidateParametersHandler.Fn(req)
|
||||
if req.Error != nil {
|
||||
t.Fatalf("expect no error, got %v", req.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMissingRequiredParameters(t *testing.T) {
|
||||
input := &StructShape{}
|
||||
req := testSvc.NewRequest(&request.Operation{}, input, nil)
|
||||
corehandlers.ValidateParametersHandler.Fn(req)
|
||||
|
||||
if req.Error == nil {
|
||||
t.Fatalf("expect error")
|
||||
}
|
||||
if e, a := "InvalidParameter", req.Error.(awserr.Error).Code(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "3 validation error(s) found.", req.Error.(awserr.Error).Message(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
|
||||
errs := req.Error.(awserr.BatchedErrors).OrigErrs()
|
||||
if e, a := 3, len(errs); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "ParamRequiredError: missing required field, StructShape.RequiredList.", errs[0].Error(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "ParamRequiredError: missing required field, StructShape.RequiredMap.", errs[1].Error(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "ParamRequiredError: missing required field, StructShape.RequiredBool.", errs[2].Error(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
|
||||
if e, a := "InvalidParameter: 3 validation error(s) found.\n- missing required field, StructShape.RequiredList.\n- missing required field, StructShape.RequiredMap.\n- missing required field, StructShape.RequiredBool.\n", req.Error.Error(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNestedMissingRequiredParameters(t *testing.T) {
|
||||
input := &StructShape{
|
||||
RequiredList: []*ConditionalStructShape{{}},
|
||||
RequiredMap: map[string]*ConditionalStructShape{
|
||||
"key1": {Name: aws.String("Name")},
|
||||
"key2": {},
|
||||
},
|
||||
RequiredBool: aws.Bool(true),
|
||||
OptionalStruct: &ConditionalStructShape{},
|
||||
}
|
||||
|
||||
req := testSvc.NewRequest(&request.Operation{}, input, nil)
|
||||
corehandlers.ValidateParametersHandler.Fn(req)
|
||||
|
||||
if req.Error == nil {
|
||||
t.Fatalf("expect error")
|
||||
}
|
||||
if e, a := "InvalidParameter", req.Error.(awserr.Error).Code(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "3 validation error(s) found.", req.Error.(awserr.Error).Message(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
|
||||
errs := req.Error.(awserr.BatchedErrors).OrigErrs()
|
||||
if e, a := 3, len(errs); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "ParamRequiredError: missing required field, StructShape.RequiredList[0].Name.", errs[0].Error(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "ParamRequiredError: missing required field, StructShape.RequiredMap[key2].Name.", errs[1].Error(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "ParamRequiredError: missing required field, StructShape.OptionalStruct.Name.", errs[2].Error(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
type testInput struct {
|
||||
StringField *string `min:"5"`
|
||||
ListField []string `min:"3"`
|
||||
MapField map[string]string `min:"4"`
|
||||
}
|
||||
|
||||
func (s testInput) Validate() error {
|
||||
invalidParams := request.ErrInvalidParams{Context: "testInput"}
|
||||
if s.StringField != nil && len(*s.StringField) < 5 {
|
||||
invalidParams.Add(request.NewErrParamMinLen("StringField", 5))
|
||||
}
|
||||
if s.ListField != nil && len(s.ListField) < 3 {
|
||||
invalidParams.Add(request.NewErrParamMinLen("ListField", 3))
|
||||
}
|
||||
if s.MapField != nil && len(s.MapField) < 4 {
|
||||
invalidParams.Add(request.NewErrParamMinLen("MapField", 4))
|
||||
}
|
||||
|
||||
if invalidParams.Len() > 0 {
|
||||
return invalidParams
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var testsFieldMin = []struct {
|
||||
err awserr.Error
|
||||
in testInput
|
||||
}{
|
||||
{
|
||||
err: func() awserr.Error {
|
||||
invalidParams := request.ErrInvalidParams{Context: "testInput"}
|
||||
invalidParams.Add(request.NewErrParamMinLen("StringField", 5))
|
||||
return invalidParams
|
||||
}(),
|
||||
in: testInput{StringField: aws.String("abcd")},
|
||||
},
|
||||
{
|
||||
err: func() awserr.Error {
|
||||
invalidParams := request.ErrInvalidParams{Context: "testInput"}
|
||||
invalidParams.Add(request.NewErrParamMinLen("StringField", 5))
|
||||
invalidParams.Add(request.NewErrParamMinLen("ListField", 3))
|
||||
return invalidParams
|
||||
}(),
|
||||
in: testInput{StringField: aws.String("abcd"), ListField: []string{"a", "b"}},
|
||||
},
|
||||
{
|
||||
err: func() awserr.Error {
|
||||
invalidParams := request.ErrInvalidParams{Context: "testInput"}
|
||||
invalidParams.Add(request.NewErrParamMinLen("StringField", 5))
|
||||
invalidParams.Add(request.NewErrParamMinLen("ListField", 3))
|
||||
invalidParams.Add(request.NewErrParamMinLen("MapField", 4))
|
||||
return invalidParams
|
||||
}(),
|
||||
in: testInput{StringField: aws.String("abcd"), ListField: []string{"a", "b"}, MapField: map[string]string{"a": "a", "b": "b"}},
|
||||
},
|
||||
{
|
||||
err: nil,
|
||||
in: testInput{StringField: aws.String("abcde"),
|
||||
ListField: []string{"a", "b", "c"}, MapField: map[string]string{"a": "a", "b": "b", "c": "c", "d": "d"}},
|
||||
},
|
||||
}
|
||||
|
||||
func TestValidateFieldMinParameter(t *testing.T) {
|
||||
for i, c := range testsFieldMin {
|
||||
req := testSvc.NewRequest(&request.Operation{}, &c.in, nil)
|
||||
corehandlers.ValidateParametersHandler.Fn(req)
|
||||
|
||||
if e, a := c.err, req.Error; !reflect.DeepEqual(e,a) {
|
||||
t.Errorf("%d, expect %v, got %v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkValidateAny(b *testing.B) {
|
||||
input := &kinesis.PutRecordsInput{
|
||||
StreamName: aws.String("stream"),
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
record := &kinesis.PutRecordsRequestEntry{
|
||||
Data: make([]byte, 10000),
|
||||
PartitionKey: aws.String("partition"),
|
||||
}
|
||||
input.Records = append(input.Records, record)
|
||||
}
|
||||
|
||||
req, _ := kinesis.New(unit.Session).PutRecordsRequest(input)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
corehandlers.ValidateParametersHandler.Fn(req)
|
||||
if err := req.Error; err != nil {
|
||||
b.Fatalf("validation failed: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
37
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent.go
generated
vendored
Normal file
37
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
package corehandlers
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// SDKVersionUserAgentHandler is a request handler for adding the SDK Version
|
||||
// to the user agent.
|
||||
var SDKVersionUserAgentHandler = request.NamedHandler{
|
||||
Name: "core.SDKVersionUserAgentHandler",
|
||||
Fn: request.MakeAddToUserAgentHandler(aws.SDKName, aws.SDKVersion,
|
||||
runtime.Version(), runtime.GOOS, runtime.GOARCH),
|
||||
}
|
||||
|
||||
const execEnvVar = `AWS_EXECUTION_ENV`
|
||||
const execEnvUAKey = `exec-env`
|
||||
|
||||
// AddHostExecEnvUserAgentHander is a request handler appending the SDK's
|
||||
// execution environment to the user agent.
|
||||
//
|
||||
// If the environment variable AWS_EXECUTION_ENV is set, its value will be
|
||||
// appended to the user agent string.
|
||||
var AddHostExecEnvUserAgentHander = request.NamedHandler{
|
||||
Name: "core.AddHostExecEnvUserAgentHander",
|
||||
Fn: func(r *request.Request) {
|
||||
v := os.Getenv(execEnvVar)
|
||||
if len(v) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
request.AddToUserAgent(r, execEnvUAKey+"/"+v)
|
||||
},
|
||||
}
|
4
vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go
generated
vendored
4
vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go
generated
vendored
|
@ -9,9 +9,7 @@ var (
|
|||
// providers in the ChainProvider.
|
||||
//
|
||||
// This has been deprecated. For verbose error messaging set
|
||||
// aws.Config.CredentialsChainVerboseErrors to true
|
||||
//
|
||||
// @readonly
|
||||
// aws.Config.CredentialsChainVerboseErrors to true.
|
||||
ErrNoValidProvidersFoundInChain = awserr.New("NoCredentialProviders",
|
||||
`no valid providers in chain. Deprecated.
|
||||
For verbose messaging see aws.Config.CredentialsChainVerboseErrors`,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue