mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-01-20 07:19:17 +01:00
vmctl: support of the remote read protocol (#3232)
vmctl: support of the remote read protocol Signed-off-by: hagen1778 <roman@victoriametrics.com> Co-authored-by: hagen1778 <roman@victoriametrics.com>
This commit is contained in:
parent
b2f45b4856
commit
002c028f22
@ -7,9 +7,12 @@ vmctl provides various useful actions with VictoriaMetrics components.
|
|||||||
Features:
|
Features:
|
||||||
- migrate data from [Prometheus](#migrating-data-from-prometheus) to VictoriaMetrics using snapshot API
|
- migrate data from [Prometheus](#migrating-data-from-prometheus) to VictoriaMetrics using snapshot API
|
||||||
- migrate data from [Thanos](#migrating-data-from-thanos) to VictoriaMetrics
|
- migrate data from [Thanos](#migrating-data-from-thanos) to VictoriaMetrics
|
||||||
|
- migrate data from [Cortex](#migrating-data-from-cortex) to VictoriaMetrics
|
||||||
|
- migrate data from [Mimir](#migrating-data-from-mimir) to VictoriaMetrics
|
||||||
- migrate data from [InfluxDB](#migrating-data-from-influxdb-1x) to VictoriaMetrics
|
- migrate data from [InfluxDB](#migrating-data-from-influxdb-1x) to VictoriaMetrics
|
||||||
- migrate data from [OpenTSDB](#migrating-data-from-opentsdb) to VictoriaMetrics
|
- migrate data from [OpenTSDB](#migrating-data-from-opentsdb) to VictoriaMetrics
|
||||||
- migrate data between [VictoriaMetrics](#migrating-data-from-victoriametrics) single or cluster version.
|
- migrate data between [VictoriaMetrics](#migrating-data-from-victoriametrics) single or cluster version.
|
||||||
|
- migrate data by [Prometheus remote read protocol](#migrating-data-by-remote-read-protocol) to VictoriaMetrics
|
||||||
- [verify](#verifying-exported-blocks-from-victoriametrics) exported blocks from VictoriaMetrics single or cluster version.
|
- [verify](#verifying-exported-blocks-from-victoriametrics) exported blocks from VictoriaMetrics single or cluster version.
|
||||||
|
|
||||||
To see the full list of supported modes
|
To see the full list of supported modes
|
||||||
@ -28,6 +31,7 @@ COMMANDS:
|
|||||||
influx Migrate timeseries from InfluxDB
|
influx Migrate timeseries from InfluxDB
|
||||||
prometheus Migrate timeseries from Prometheus
|
prometheus Migrate timeseries from Prometheus
|
||||||
vm-native Migrate time series between VictoriaMetrics installations via native binary format
|
vm-native Migrate time series between VictoriaMetrics installations via native binary format
|
||||||
|
remote-read Migrate timeseries by Prometheus remote read protocol
|
||||||
verify-block Verifies correctness of data blocks exported via VictoriaMetrics Native format. See https://docs.victoriametrics.com/#how-to-export-data-in-native-format
|
verify-block Verifies correctness of data blocks exported via VictoriaMetrics Native format. See https://docs.victoriametrics.com/#how-to-export-data-in-native-format
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -432,6 +436,64 @@ Found 2 blocks to import. Continue? [Y/n] y
|
|||||||
2020/02/23 15:51:07 Total time: 7.153158218s
|
2020/02/23 15:51:07 Total time: 7.153158218s
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Migrating data by remote read protocol
|
||||||
|
|
||||||
|
`vmctl` supports the `remote-read` mode for migrating data from databases which support
|
||||||
|
[Prometheus remote read API](https://prometheus.io/docs/prometheus/latest/querying/remote_read_api/)
|
||||||
|
|
||||||
|
See `./vmctl remote-read --help` for details and full list of flags.
|
||||||
|
|
||||||
|
To start the migration process configure the following flags:
|
||||||
|
1. `--remote-read-src-addr` - data source address to read from;
|
||||||
|
2. `--vm-addr` - VictoriaMetrics address to write to. For single-node VM is usually equal to `--httpListenAddr`,
|
||||||
|
and for cluster version is equal to `--httpListenAddr` flag of vminsert component (for example `http://<vminsert>:8480/insert/<accountID>/prometheus`);
|
||||||
|
3. `--remote-read-filter-time-start` - the time filter in RFC3339 format to select time series with timestamp equal or higher than provided value. E.g. '2020-01-01T20:07:00Z';
|
||||||
|
4. `--remote-read-filter-time-end` - the time filter in RFC3339 format to select time series with timestamp equal or smaller than provided value. E.g. '2020-01-01T20:07:00Z'. Current time is used when omitted.;
|
||||||
|
5. `--remote-read-step-interval` - split export data into chunks. Valid values are `month, day, hour, minute`;
|
||||||
|
|
||||||
|
The importing process example for local installation of Prometheus
|
||||||
|
and single-node VictoriaMetrics(`http://localhost:8428`):
|
||||||
|
|
||||||
|
```
|
||||||
|
./vmctl remote-read \
|
||||||
|
--remote-read-src-addr=http://127.0.0.1:9091 \
|
||||||
|
--remote-read-filter-time-start=2021-10-18T00:00:00Z \
|
||||||
|
--remote-read-step-interval=hour \
|
||||||
|
--vm-addr=http://127.0.0.1:8428 \
|
||||||
|
--vm-concurrency=6
|
||||||
|
|
||||||
|
Split defined times into 8798 ranges to import. Continue? [Y/n]
|
||||||
|
VM worker 0:↘ 127177 samples/s
|
||||||
|
VM worker 1:↘ 140137 samples/s
|
||||||
|
VM worker 2:↘ 151606 samples/s
|
||||||
|
VM worker 3:↘ 130765 samples/s
|
||||||
|
VM worker 4:↘ 131904 samples/s
|
||||||
|
VM worker 5:↘ 132693 samples/s
|
||||||
|
Processing ranges: 8798 / 8798 [█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████] 100.00%
|
||||||
|
2022/10/19 16:45:37 Import finished!
|
||||||
|
2022/10/19 16:45:37 VictoriaMetrics importer stats:
|
||||||
|
idle duration: 6m57.793987511s;
|
||||||
|
time spent while importing: 1m18.463744801s;
|
||||||
|
total samples: 25348208;
|
||||||
|
samples/s: 323056.31;
|
||||||
|
total bytes: 669.7 MB;
|
||||||
|
bytes/s: 8.5 MB;
|
||||||
|
import requests: 127;
|
||||||
|
import requests retries: 0;
|
||||||
|
2022/10/19 16:45:37 Total time: 1m19.406283424s
|
||||||
|
```
|
||||||
|
|
||||||
|
### Filtering
|
||||||
|
|
||||||
|
The filtering consists of two parts: by labels and time.
|
||||||
|
|
||||||
|
Filtering by time can be configured via flags `--remote-read-filter-time-start` and `--remote-read-filter-time-end`
|
||||||
|
in RFC3339 format.
|
||||||
|
|
||||||
|
Filtering by labels can be configured via flags `--remote-read-filter-label` and `--remote-read-filter-label-value`.
|
||||||
|
For example, `--remote-read-filter-label=tenant` and `--remote-read-filter-label-value="team-eu"` will select only series
|
||||||
|
with `tenant="team-eu"` label-value pair.
|
||||||
|
|
||||||
## Migrating data from Thanos
|
## Migrating data from Thanos
|
||||||
|
|
||||||
Thanos uses the same storage engine as Prometheus and the data layout on-disk should be the same. That means
|
Thanos uses the same storage engine as Prometheus and the data layout on-disk should be the same. That means
|
||||||
@ -478,6 +540,187 @@ then import it into VM using `vmctl` in `prometheus` mode.
|
|||||||
vmctl prometheus --prom-snapshot thanos-data --vm-addr http://victoria-metrics:8428
|
vmctl prometheus --prom-snapshot thanos-data --vm-addr http://victoria-metrics:8428
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Remote read protocol
|
||||||
|
|
||||||
|
Currently, Thanos doesn't support streaming remote read protocol. It is [recommended](https://thanos.io/tip/thanos/integrations.md/#storeapi-as-prometheus-remote-read)
|
||||||
|
to use [thanos-remote-read](https://github.com/G-Research/thanos-remote-read) a proxy, that allows exposing any Thanos
|
||||||
|
service (or anything that exposes gRPC StoreAPI e.g. Querier) via Prometheus remote read protocol.
|
||||||
|
|
||||||
|
If you want to migrate data, you should run [thanos-remote-read](https://github.com/G-Research/thanos-remote-read) proxy
|
||||||
|
and define the Thanos store address `./thanos-remote-read -store 127.0.0.1:19194`.
|
||||||
|
It is important to know that `store` flag is Thanos Store API gRPC endpoint.
|
||||||
|
Also, it is important to know that thanos-remote-read proxy doesn't support `STREAMED_XOR_CHUNKS` mode.
|
||||||
|
When you run thanos-remote-read proxy, it exposes port to serve HTTP on `10080 by default`.
|
||||||
|
|
||||||
|
The importing process example for local installation of Thanos
|
||||||
|
and single-node VictoriaMetrics(`http://localhost:8428`):
|
||||||
|
|
||||||
|
```
|
||||||
|
./vmctl remote-read \
|
||||||
|
--remote-read-src-addr=http://127.0.0.1:10080 \
|
||||||
|
--remote-read-filter-time-start=2021-10-18T00:00:00Z \
|
||||||
|
--remote-read-step-interval=hour \
|
||||||
|
--vm-addr=http://127.0.0.1:8428 \
|
||||||
|
--vm-concurrency=6
|
||||||
|
```
|
||||||
|
|
||||||
|
On the [thanos-remote-read](https://github.com/G-Research/thanos-remote-read) proxy side you will see logs like:
|
||||||
|
```
|
||||||
|
ts=2022-10-19T15:05:04.193916Z caller=main.go:278 level=info traceID=00000000000000000000000000000000 msg="thanos request" request="min_time:1666180800000 max_time:1666184399999 matchers:<type:RE value:\".*\" > aggregates:RAW "
|
||||||
|
ts=2022-10-19T15:05:04.468852Z caller=main.go:278 level=info traceID=00000000000000000000000000000000 msg="thanos request" request="min_time:1666184400000 max_time:1666187999999 matchers:<type:RE value:\".*\" > aggregates:RAW "
|
||||||
|
ts=2022-10-19T15:05:04.553914Z caller=main.go:278 level=info traceID=00000000000000000000000000000000 msg="thanos request" request="min_time:1666188000000 max_time:1666191364863 matchers:<type:RE value:\".*\" > aggregates:RAW "
|
||||||
|
```
|
||||||
|
|
||||||
|
And when process will finish you will see:
|
||||||
|
```
|
||||||
|
Split defined times into 8799 ranges to import. Continue? [Y/n]
|
||||||
|
VM worker 0:↓ 98183 samples/s
|
||||||
|
VM worker 1:↓ 114640 samples/s
|
||||||
|
VM worker 2:↓ 131710 samples/s
|
||||||
|
VM worker 3:↓ 114256 samples/s
|
||||||
|
VM worker 4:↓ 105671 samples/s
|
||||||
|
VM worker 5:↓ 124000 samples/s
|
||||||
|
Processing ranges: 8799 / 8799 [█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████] 100.00%
|
||||||
|
2022/10/19 18:05:07 Import finished!
|
||||||
|
2022/10/19 18:05:07 VictoriaMetrics importer stats:
|
||||||
|
idle duration: 52m13.987637229s;
|
||||||
|
time spent while importing: 9m1.728983776s;
|
||||||
|
total samples: 70836111;
|
||||||
|
samples/s: 130759.32;
|
||||||
|
total bytes: 2.2 GB;
|
||||||
|
bytes/s: 4.0 MB;
|
||||||
|
import requests: 356;
|
||||||
|
import requests retries: 0;
|
||||||
|
2022/10/19 18:05:07 Total time: 9m2.607521618s
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migrating data from Cortex
|
||||||
|
|
||||||
|
Cortex has an implementation of the Prometheus remote read protocol. That means
|
||||||
|
`vmctl` in mode `remote-read` may also be used for Cortex historical data migration.
|
||||||
|
These instructions may vary based on the details of your Cortex configuration.
|
||||||
|
Please read carefully and verify as you go.
|
||||||
|
|
||||||
|
### Remote read protocol
|
||||||
|
|
||||||
|
If you want to migrate data, you should check your cortex configuration in the section
|
||||||
|
```yaml
|
||||||
|
api:
|
||||||
|
prometheus_http_prefix:
|
||||||
|
```
|
||||||
|
|
||||||
|
If you defined some prometheus prefix, you should use it when you define flag `--remote-read-src-addr=http://127.0.0.1:9009/{prometheus_http_prefix}`.
|
||||||
|
By default, Cortex uses the `prometheus` path prefix, so you should define the flag `--remote-read-src-addr=http://127.0.0.1:9009/prometheus`.
|
||||||
|
|
||||||
|
It is important to know that Cortex doesn't support the `STREAMED_XOR_CHUNKS` mode.
|
||||||
|
When you run Cortex, it exposes a port to serve HTTP on `9009 by default`.
|
||||||
|
|
||||||
|
The importing process example for the local installation of Cortex
|
||||||
|
and single-node VictoriaMetrics(`http://localhost:8428`):
|
||||||
|
|
||||||
|
```
|
||||||
|
./vmctl remote-read \
|
||||||
|
--remote-read-src-addr=http://127.0.0.1:9009/prometheus \
|
||||||
|
--remote-read-filter-time-start=2021-10-18T00:00:00Z \
|
||||||
|
--remote-read-step-interval=hour \
|
||||||
|
--remote-read-src-check-alive=false \
|
||||||
|
--vm-addr=http://127.0.0.1:8428 \
|
||||||
|
--vm-concurrency=6
|
||||||
|
```
|
||||||
|
And when the process finishes, you will see the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
Split defined times into 8842 ranges to import. Continue? [Y/n]
|
||||||
|
VM worker 0:↗ 3863 samples/s
|
||||||
|
VM worker 1:↗ 2686 samples/s
|
||||||
|
VM worker 2:↗ 2620 samples/s
|
||||||
|
VM worker 3:↗ 2705 samples/s
|
||||||
|
VM worker 4:↗ 2643 samples/s
|
||||||
|
VM worker 5:↗ 2593 samples/s
|
||||||
|
Processing ranges: 8842 / 8842 [█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████] 100.00%
|
||||||
|
2022/10/21 12:09:49 Import finished!
|
||||||
|
2022/10/21 12:09:49 VictoriaMetrics importer stats:
|
||||||
|
idle duration: 0s;
|
||||||
|
time spent while importing: 3.82640757s;
|
||||||
|
total samples: 160232;
|
||||||
|
samples/s: 41875.31;
|
||||||
|
total bytes: 11.3 MB;
|
||||||
|
bytes/s: 3.0 MB;
|
||||||
|
import requests: 6;
|
||||||
|
import requests retries: 0;
|
||||||
|
2022/10/21 12:09:49 Total time: 4.71824253s
|
||||||
|
```
|
||||||
|
It is important to know that if you run your Cortex installation in multi-tenant mode, remote read protocol
|
||||||
|
requires an Authentication header like `X-Scope-OrgID`. You can define it via the flag `--remote-read-headers=X-Scope-OrgID:demo`
|
||||||
|
|
||||||
|
## Migrating data from Mimir
|
||||||
|
|
||||||
|
Mimir has similar implemintation as Cortex and also support of the Prometheus remote read protocol. That means
|
||||||
|
`vmctl` in mode `remote-read` may also be used for Mimir historical data migration.
|
||||||
|
These instructions may vary based on the details of your Mimir configuration.
|
||||||
|
Please read carefully and verify as you go.
|
||||||
|
|
||||||
|
### Remote read protocol
|
||||||
|
|
||||||
|
If you want to migrate data, you should check your Mimir configuration in the section
|
||||||
|
```yaml
|
||||||
|
api:
|
||||||
|
prometheus_http_prefix:
|
||||||
|
```
|
||||||
|
|
||||||
|
If you defined some prometheus prefix, you should use it when you define flag `--remote-read-src-addr=http://127.0.0.1:9009/{prometheus_http_prefix}`.
|
||||||
|
By default, Mimir uses the `prometheus` path prefix, so you should define the flag `--remote-read-src-addr=http://127.0.0.1:9009/prometheus`.
|
||||||
|
|
||||||
|
Mimir supports both remote read mode, so you can use `STREAMED_XOR_CHUNKS` mode and `SAMPLES` mode.
|
||||||
|
When you run Mimir, it exposes a port to serve HTTP on `8080 by default`.
|
||||||
|
|
||||||
|
Next example of the local installation was in multi-tenant mode (3 instances of mimir) with nginx as load balancer.
|
||||||
|
Load balancer expose single port `:9090`.
|
||||||
|
|
||||||
|
As you can see in the example we call `:9009` instead of `:8080` because of proxy.
|
||||||
|
|
||||||
|
The importing process example for the local installation of Mimir
|
||||||
|
and single-node VictoriaMetrics(`http://localhost:8428`):
|
||||||
|
|
||||||
|
```
|
||||||
|
./vmctl remote-read
|
||||||
|
--remote-read-src-addr=http://127.0.0.1:9009/prometheus \
|
||||||
|
--remote-read-filter-time-start=2021-10-18T00:00:00Z \
|
||||||
|
--remote-read-step-interval=hour \
|
||||||
|
--remote-read-src-check-alive=false \
|
||||||
|
--remote-read-headers=X-Scope-OrgID:demo \
|
||||||
|
--remote-read-use-stream=true \
|
||||||
|
--vm-addr=http://127.0.0.1:8428 \
|
||||||
|
--vm-concurrency=6
|
||||||
|
```
|
||||||
|
|
||||||
|
And when the process finishes, you will see the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
Split defined times into 8847 ranges to import. Continue? [Y/n]
|
||||||
|
VM worker 0:→ 12176 samples/s
|
||||||
|
VM worker 1:→ 11918 samples/s
|
||||||
|
VM worker 2:→ 11261 samples/s
|
||||||
|
VM worker 3:→ 12861 samples/s
|
||||||
|
VM worker 4:→ 11096 samples/s
|
||||||
|
VM worker 5:→ 11575 samples/s
|
||||||
|
Processing ranges: 8847 / 8847 [█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████] 100.00%
|
||||||
|
2022/10/21 17:22:23 Import finished!
|
||||||
|
2022/10/21 17:22:23 VictoriaMetrics importer stats:
|
||||||
|
idle duration: 0s;
|
||||||
|
time spent while importing: 15.379614356s;
|
||||||
|
total samples: 81243;
|
||||||
|
samples/s: 5282.51;
|
||||||
|
total bytes: 6.1 MB;
|
||||||
|
bytes/s: 397.8 kB;
|
||||||
|
import requests: 6;
|
||||||
|
import requests retries: 0;
|
||||||
|
2022/10/21 17:22:23 Total time: 16.287405248s
|
||||||
|
```
|
||||||
|
|
||||||
|
It is important to know that if you run your Mimir installation in multi-tenant mode, remote read protocol
|
||||||
|
requires an Authentication header like `X-Scope-OrgID`. You can define it via the flag `--remote-read-headers=X-Scope-OrgID:demo`
|
||||||
|
|
||||||
## Migrating data from VictoriaMetrics
|
## Migrating data from VictoriaMetrics
|
||||||
|
|
||||||
### Native protocol
|
### Native protocol
|
||||||
|
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
@ -400,6 +401,93 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
remoteRead = "remote-read"
|
||||||
|
remoteReadUseStream = "remote-read-use-stream"
|
||||||
|
remoteReadConcurrency = "remote-read-concurrency"
|
||||||
|
remoteReadFilterTimeStart = "remote-read-filter-time-start"
|
||||||
|
remoteReadFilterTimeEnd = "remote-read-filter-time-end"
|
||||||
|
remoteReadFilterLabel = "remote-read-filter-label"
|
||||||
|
remoteReadFilterLabelValue = "remote-read-filter-label-value"
|
||||||
|
remoteReadStepInterval = "remote-read-step-interval"
|
||||||
|
remoteReadSrcAddr = "remote-read-src-addr"
|
||||||
|
remoteReadUser = "remote-read-user"
|
||||||
|
remoteReadPassword = "remote-read-password"
|
||||||
|
remoteReadHTTPTimeout = "remote-read-http-timeout"
|
||||||
|
remoteReadHeaders = "remote-read-headers"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
remoteReadFlags = []cli.Flag{
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: remoteReadConcurrency,
|
||||||
|
Usage: "Number of concurrently running remote read readers",
|
||||||
|
Value: 1,
|
||||||
|
},
|
||||||
|
&cli.TimestampFlag{
|
||||||
|
Name: remoteReadFilterTimeStart,
|
||||||
|
Usage: "The time filter in RFC3339 format to select timeseries with timestamp equal or higher than provided value. E.g. '2020-01-01T20:07:00Z'",
|
||||||
|
Layout: time.RFC3339,
|
||||||
|
},
|
||||||
|
&cli.TimestampFlag{
|
||||||
|
Name: remoteReadFilterTimeEnd,
|
||||||
|
Usage: "The time filter in RFC3339 format to select timeseries with timestamp equal or lower than provided value. E.g. '2020-01-01T20:07:00Z'",
|
||||||
|
Layout: time.RFC3339,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: remoteReadFilterLabel,
|
||||||
|
Usage: "Prometheus label name to filter timeseries by. E.g. '__name__' will filter timeseries by name.",
|
||||||
|
Value: "__name__",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: remoteReadFilterLabelValue,
|
||||||
|
Usage: fmt.Sprintf("Prometheus regular expression to filter label from %q flag.", remoteReadFilterLabelValue),
|
||||||
|
Value: ".*",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: remoteRead,
|
||||||
|
Usage: "Use Prometheus remote read protocol",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: remoteReadUseStream,
|
||||||
|
Usage: "Defines whether to use SAMPLES or STREAMED_XOR_CHUNKS mode. By default is uses SAMPLES mode. See https://prometheus.io/docs/prometheus/latest/querying/remote_read_api/#streamed-chunks",
|
||||||
|
Value: false,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: remoteReadStepInterval,
|
||||||
|
Usage: fmt.Sprintf("Split export data into chunks. Requires setting --%s. Valid values are %q,%q,%q,%q.", remoteReadFilterTimeStart, stepper.StepMonth, stepper.StepDay, stepper.StepHour, stepper.StepMinute),
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: remoteReadSrcAddr,
|
||||||
|
Usage: "Remote read address to perform read from.",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: remoteReadUser,
|
||||||
|
Usage: "Remote read username for basic auth",
|
||||||
|
EnvVars: []string{"REMOTE_READ_USERNAME"},
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: remoteReadPassword,
|
||||||
|
Usage: "Remote read password for basic auth",
|
||||||
|
EnvVars: []string{"REMOTE_READ_PASSWORD"},
|
||||||
|
},
|
||||||
|
&cli.DurationFlag{
|
||||||
|
Name: remoteReadHTTPTimeout,
|
||||||
|
Usage: "Timeout defines timeout for HTTP write request to remote storage",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: remoteReadHeaders,
|
||||||
|
Value: "",
|
||||||
|
Usage: "Optional HTTP headers to send with each request to the corresponding remote source storage \n" +
|
||||||
|
"For example, --remote-read-headers='My-Auth:foobar' would send 'My-Auth: foobar' HTTP header with every request to the corresponding remote source storage. \n" +
|
||||||
|
"Multiple headers must be delimited by '^^': --remote-read-headers='header1:value1^^header2:value2'",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func mergeFlags(flags ...[]cli.Flag) []cli.Flag {
|
func mergeFlags(flags ...[]cli.Flag) []cli.Flag {
|
||||||
var result []cli.Flag
|
var result []cli.Flag
|
||||||
for _, f := range flags {
|
for _, f := range flags {
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/remoteread"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/influx"
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/influx"
|
||||||
@ -40,7 +41,7 @@ func main() {
|
|||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "opentsdb",
|
Name: "opentsdb",
|
||||||
Usage: "Migrate timeseries from OpenTSDB",
|
Usage: "Migrate time series from OpenTSDB",
|
||||||
Flags: mergeFlags(globalFlags, otsdbFlags, vmFlags),
|
Flags: mergeFlags(globalFlags, otsdbFlags, vmFlags),
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
fmt.Println("OpenTSDB import mode")
|
fmt.Println("OpenTSDB import mode")
|
||||||
@ -75,7 +76,7 @@ func main() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "influx",
|
Name: "influx",
|
||||||
Usage: "Migrate timeseries from InfluxDB",
|
Usage: "Migrate time series from InfluxDB",
|
||||||
Flags: mergeFlags(globalFlags, influxFlags, vmFlags),
|
Flags: mergeFlags(globalFlags, influxFlags, vmFlags),
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
fmt.Println("InfluxDB import mode")
|
fmt.Println("InfluxDB import mode")
|
||||||
@ -114,9 +115,48 @@ func main() {
|
|||||||
return processor.run(c.Bool(globalSilent), c.Bool(globalVerbose))
|
return processor.run(c.Bool(globalSilent), c.Bool(globalVerbose))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "remote-read",
|
||||||
|
Usage: "Migrate time series via Prometheus remote-read protocol",
|
||||||
|
Flags: mergeFlags(globalFlags, remoteReadFlags, vmFlags),
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
rr, err := remoteread.NewClient(remoteread.Config{
|
||||||
|
Addr: c.String(remoteReadSrcAddr),
|
||||||
|
Username: c.String(remoteReadUser),
|
||||||
|
Password: c.String(remoteReadPassword),
|
||||||
|
Timeout: c.Duration(remoteReadHTTPTimeout),
|
||||||
|
UseStream: c.Bool(remoteReadUseStream),
|
||||||
|
Headers: c.String(remoteReadHeaders),
|
||||||
|
LabelName: c.String(remoteReadFilterLabel),
|
||||||
|
LabelValue: c.String(remoteReadFilterLabelValue),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error create remote read client: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vmCfg := initConfigVM(c)
|
||||||
|
|
||||||
|
importer, err := vm.NewImporter(vmCfg)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create VM importer: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rmp := remoteReadProcessor{
|
||||||
|
src: rr,
|
||||||
|
dst: importer,
|
||||||
|
filter: remoteReadFilter{
|
||||||
|
timeStart: c.Timestamp(remoteReadFilterTimeStart),
|
||||||
|
timeEnd: c.Timestamp(remoteReadFilterTimeEnd),
|
||||||
|
chunk: c.String(remoteReadStepInterval),
|
||||||
|
},
|
||||||
|
cc: c.Int(remoteReadConcurrency),
|
||||||
|
}
|
||||||
|
return rmp.run(ctx, c.Bool(globalSilent), c.Bool(globalVerbose))
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "prometheus",
|
Name: "prometheus",
|
||||||
Usage: "Migrate timeseries from Prometheus",
|
Usage: "Migrate time series from Prometheus",
|
||||||
Flags: mergeFlags(globalFlags, promFlags, vmFlags),
|
Flags: mergeFlags(globalFlags, promFlags, vmFlags),
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
fmt.Println("Prometheus import mode")
|
fmt.Println("Prometheus import mode")
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/pkg/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
"github.com/prometheus/prometheus/tsdb"
|
"github.com/prometheus/prometheus/tsdb"
|
||||||
)
|
)
|
||||||
|
127
app/vmctl/remoteread.go
Normal file
127
app/vmctl/remoteread.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/barpool"
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/remoteread"
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/stepper"
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/vm"
|
||||||
|
"github.com/cheggaaa/pb/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type remoteReadProcessor struct {
|
||||||
|
filter remoteReadFilter
|
||||||
|
|
||||||
|
dst *vm.Importer
|
||||||
|
src *remoteread.Client
|
||||||
|
|
||||||
|
cc int
|
||||||
|
}
|
||||||
|
|
||||||
|
type remoteReadFilter struct {
|
||||||
|
timeStart *time.Time
|
||||||
|
timeEnd *time.Time
|
||||||
|
chunk string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rrp *remoteReadProcessor) run(ctx context.Context, silent, verbose bool) error {
|
||||||
|
rrp.dst.ResetStats()
|
||||||
|
if rrp.filter.timeEnd == nil {
|
||||||
|
t := time.Now().In(rrp.filter.timeStart.Location())
|
||||||
|
rrp.filter.timeEnd = &t
|
||||||
|
}
|
||||||
|
if rrp.cc < 1 {
|
||||||
|
rrp.cc = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ranges, err := stepper.SplitDateRange(*rrp.filter.timeStart, *rrp.filter.timeEnd, rrp.filter.chunk)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create date ranges for the given time filters: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
question := fmt.Sprintf("Selected time range %q - %q will be split into %d ranges according to %q step. Continue?",
|
||||||
|
rrp.filter.timeStart.String(), rrp.filter.timeEnd.String(), len(ranges), rrp.filter.chunk)
|
||||||
|
if !silent && !prompt(question) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var bar *pb.ProgressBar
|
||||||
|
if !silent {
|
||||||
|
bar = barpool.AddWithTemplate(fmt.Sprintf(barTpl, "Processing ranges"), len(ranges))
|
||||||
|
if err := barpool.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if !silent {
|
||||||
|
barpool.Stop()
|
||||||
|
}
|
||||||
|
log.Println("Import finished!")
|
||||||
|
log.Print(rrp.dst.Stats())
|
||||||
|
}()
|
||||||
|
|
||||||
|
rangeC := make(chan *remoteread.Filter)
|
||||||
|
errCh := make(chan error)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(rrp.cc)
|
||||||
|
for i := 0; i < rrp.cc; i++ {
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
for r := range rangeC {
|
||||||
|
if err := rrp.do(ctx, r); err != nil {
|
||||||
|
errCh <- fmt.Errorf("request failed for: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if bar != nil {
|
||||||
|
bar.Increment()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range ranges {
|
||||||
|
select {
|
||||||
|
case infErr := <-errCh:
|
||||||
|
return fmt.Errorf("remote read error: %s", infErr)
|
||||||
|
case vmErr := <-rrp.dst.Errors():
|
||||||
|
return fmt.Errorf("import process failed: %s", wrapErr(vmErr, verbose))
|
||||||
|
case rangeC <- &remoteread.Filter{
|
||||||
|
StartTimestampMs: r[0].UnixMilli(),
|
||||||
|
EndTimestampMs: r[1].UnixMilli(),
|
||||||
|
}:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(rangeC)
|
||||||
|
wg.Wait()
|
||||||
|
rrp.dst.Close()
|
||||||
|
close(errCh)
|
||||||
|
// drain import errors channel
|
||||||
|
for vmErr := range rrp.dst.Errors() {
|
||||||
|
if vmErr.Err != nil {
|
||||||
|
return fmt.Errorf("import process failed: %s", wrapErr(vmErr, verbose))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for err := range errCh {
|
||||||
|
return fmt.Errorf("import process failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rrp *remoteReadProcessor) do(ctx context.Context, filter *remoteread.Filter) error {
|
||||||
|
return rrp.src.Read(ctx, filter, func(series *vm.TimeSeries) error {
|
||||||
|
if err := rrp.dst.Input(series); err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"failed to read data for time range start: %d, end: %d, %s",
|
||||||
|
filter.StartTimestampMs, filter.EndTimestampMs, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
341
app/vmctl/remoteread/remoteread.go
Normal file
341
app/vmctl/remoteread/remoteread.go
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
package remoteread
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/vm"
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
"github.com/golang/snappy"
|
||||||
|
"github.com/prometheus/prometheus/prompb"
|
||||||
|
"github.com/prometheus/prometheus/storage/remote"
|
||||||
|
"github.com/prometheus/prometheus/tsdb/chunkenc"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultReadTimeout = 30 * time.Second
|
||||||
|
remoteReadPath = "/api/v1/read"
|
||||||
|
healthPath = "/-/healthy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StreamCallback is a callback function for processing time series
|
||||||
|
type StreamCallback func(series *vm.TimeSeries) error
|
||||||
|
|
||||||
|
// Client is an HTTP client for reading
|
||||||
|
// time series via remote read protocol.
|
||||||
|
type Client struct {
|
||||||
|
addr string
|
||||||
|
c *http.Client
|
||||||
|
user string
|
||||||
|
password string
|
||||||
|
useStream bool
|
||||||
|
headers []keyValue
|
||||||
|
matchers []*prompb.LabelMatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is config for remote read.
|
||||||
|
type Config struct {
|
||||||
|
// Addr of remote storage
|
||||||
|
Addr string
|
||||||
|
// Timeout defines timeout for HTTP requests
|
||||||
|
// made by remote read client
|
||||||
|
Timeout time.Duration
|
||||||
|
// Username is the remote read username, optional.
|
||||||
|
Username string
|
||||||
|
// Password is the remote read password, optional.
|
||||||
|
Password string
|
||||||
|
// UseStream defines whether to use SAMPLES or STREAMED_XOR_CHUNKS mode
|
||||||
|
// see https://prometheus.io/docs/prometheus/latest/querying/remote_read_api/#samples
|
||||||
|
// https://prometheus.io/docs/prometheus/latest/querying/remote_read_api/#streamed-chunks
|
||||||
|
UseStream bool
|
||||||
|
// Headers optional HTTP headers to send with each request to the corresponding remote storage
|
||||||
|
Headers string
|
||||||
|
// LabelName, LabelValue stands for label=~value pair used for read requests.
|
||||||
|
// Is optional.
|
||||||
|
LabelName, LabelValue string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter defines a list of filters applied to requested data
|
||||||
|
type Filter struct {
|
||||||
|
StartTimestampMs int64
|
||||||
|
EndTimestampMs int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns client for
|
||||||
|
// reading time series via remote read protocol.
|
||||||
|
func NewClient(cfg Config) (*Client, error) {
|
||||||
|
if cfg.Addr == "" {
|
||||||
|
return nil, fmt.Errorf("config.Addr can't be empty")
|
||||||
|
}
|
||||||
|
if cfg.Timeout == 0 {
|
||||||
|
cfg.Timeout = defaultReadTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
var hdrs []string
|
||||||
|
if cfg.Headers != "" {
|
||||||
|
hdrs = strings.Split(cfg.Headers, "^^")
|
||||||
|
}
|
||||||
|
|
||||||
|
headers, err := parseHeaders(hdrs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var m *prompb.LabelMatcher
|
||||||
|
if cfg.LabelName != "" && cfg.LabelValue != "" {
|
||||||
|
m = &prompb.LabelMatcher{
|
||||||
|
Type: prompb.LabelMatcher_RE,
|
||||||
|
Name: cfg.LabelName,
|
||||||
|
Value: cfg.LabelValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &Client{
|
||||||
|
c: &http.Client{
|
||||||
|
Timeout: cfg.Timeout,
|
||||||
|
Transport: http.DefaultTransport.(*http.Transport).Clone(),
|
||||||
|
},
|
||||||
|
addr: strings.TrimSuffix(cfg.Addr, "/"),
|
||||||
|
user: cfg.Username,
|
||||||
|
password: cfg.Password,
|
||||||
|
useStream: cfg.UseStream,
|
||||||
|
headers: headers,
|
||||||
|
matchers: []*prompb.LabelMatcher{m},
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read fetch data from remote read source
|
||||||
|
func (c *Client) Read(ctx context.Context, filter *Filter, streamCb StreamCallback) error {
|
||||||
|
req := &prompb.ReadRequest{
|
||||||
|
Queries: []*prompb.Query{
|
||||||
|
{
|
||||||
|
StartTimestampMs: filter.StartTimestampMs,
|
||||||
|
EndTimestampMs: filter.EndTimestampMs - 1,
|
||||||
|
Matchers: c.matchers,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if c.useStream {
|
||||||
|
req.AcceptedResponseTypes = []prompb.ReadRequest_ResponseType{prompb.ReadRequest_STREAMED_XOR_CHUNKS}
|
||||||
|
}
|
||||||
|
data, err := proto.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to marshal read request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := snappy.Encode(nil, data)
|
||||||
|
if err := c.fetch(ctx, b, streamCb); err != nil {
|
||||||
|
if errors.Is(err, context.Canceled) {
|
||||||
|
return fmt.Errorf("fetch request has ben cancelled")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("error while fetching data from remote storage: %s", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) do(req *http.Request) (*http.Response, error) {
|
||||||
|
if c.user != "" {
|
||||||
|
req.SetBasicAuth(c.user, c.password)
|
||||||
|
}
|
||||||
|
for _, h := range c.headers {
|
||||||
|
req.Header.Add(h.key, h.value)
|
||||||
|
}
|
||||||
|
return c.c.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping checks the health of the read source
|
||||||
|
func (c *Client) Ping() error {
|
||||||
|
url := c.addr + healthPath
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot create request to %q: %s", url, err)
|
||||||
|
}
|
||||||
|
resp, err := c.do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return fmt.Errorf("bad status code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) fetch(ctx context.Context, data []byte, streamCb StreamCallback) error {
|
||||||
|
r := bytes.NewReader(data)
|
||||||
|
url := c.addr + remoteReadPath
|
||||||
|
req, err := http.NewRequest("POST", url, r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create new HTTP request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add("Content-Encoding", "snappy")
|
||||||
|
req.Header.Add("Accept-Encoding", "snappy")
|
||||||
|
req.Header.Set("Content-Type", "application/x-protobuf")
|
||||||
|
if c.useStream {
|
||||||
|
req.Header.Set("Content-Type", "application/x-streamed-protobuf; proto=prometheus.ChunkedReadResponse")
|
||||||
|
}
|
||||||
|
req.Header.Set("X-Prometheus-Remote-Read-Version", "0.1.0")
|
||||||
|
|
||||||
|
resp, err := c.do(req.WithContext(ctx))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while sending request to %s: %w; Data len %d(%d)",
|
||||||
|
req.URL.Redacted(), err, len(data), r.Size())
|
||||||
|
}
|
||||||
|
defer func() { _ = resp.Body.Close() }()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return fmt.Errorf("unexpected response code %d for %s. Response body %q",
|
||||||
|
resp.StatusCode, req.URL.Redacted(), body)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.useStream {
|
||||||
|
return processStreamResponse(resp.Body, streamCb)
|
||||||
|
}
|
||||||
|
|
||||||
|
return processResponse(resp.Body, streamCb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func processResponse(body io.ReadCloser, callback StreamCallback) error {
|
||||||
|
d, err := io.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error reading response: %w", err)
|
||||||
|
}
|
||||||
|
uncompressed, err := snappy.Decode(nil, d)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error decoding response: %w", err)
|
||||||
|
}
|
||||||
|
var readResp prompb.ReadResponse
|
||||||
|
err = proto.Unmarshal(uncompressed, &readResp)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to unmarshal response body: %w", err)
|
||||||
|
}
|
||||||
|
// response could have no results for the given filter, but that
|
||||||
|
// shouldn't be accounted as an error.
|
||||||
|
for _, res := range readResp.Results {
|
||||||
|
for _, ts := range res.Timeseries {
|
||||||
|
vmTs := convertSamples(ts.Samples, ts.Labels)
|
||||||
|
if err := callback(vmTs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var bbPool bytesutil.ByteBufferPool
|
||||||
|
|
||||||
|
func processStreamResponse(body io.ReadCloser, callback StreamCallback) error {
|
||||||
|
bb := bbPool.Get()
|
||||||
|
defer func() { bbPool.Put(bb) }()
|
||||||
|
|
||||||
|
stream := remote.NewChunkedReader(body, remote.DefaultChunkedReadLimit, bb.B)
|
||||||
|
for {
|
||||||
|
res := &prompb.ChunkedReadResponse{}
|
||||||
|
err := stream.NextProto(res)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, series := range res.ChunkedSeries {
|
||||||
|
samples := make([]prompb.Sample, 0)
|
||||||
|
for _, chunk := range series.Chunks {
|
||||||
|
s, err := parseSamples(chunk.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
samples = append(samples, s...)
|
||||||
|
}
|
||||||
|
|
||||||
|
ts := convertSamples(samples, series.Labels)
|
||||||
|
if err := callback(ts); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseSamples(chunk []byte) ([]prompb.Sample, error) {
|
||||||
|
c, err := chunkenc.FromData(chunkenc.EncXOR, chunk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error read chunk: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var samples []prompb.Sample
|
||||||
|
it := c.Iterator(nil)
|
||||||
|
for it.Next() {
|
||||||
|
if it.Err() != nil {
|
||||||
|
return nil, fmt.Errorf("error iterate over chunks: %w", it.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
ts, v := it.At()
|
||||||
|
s := prompb.Sample{
|
||||||
|
Timestamp: ts,
|
||||||
|
Value: v,
|
||||||
|
}
|
||||||
|
samples = append(samples, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples, it.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
type keyValue struct {
|
||||||
|
key string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHeaders(headers []string) ([]keyValue, error) {
|
||||||
|
if len(headers) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
kvs := make([]keyValue, len(headers))
|
||||||
|
for i, h := range headers {
|
||||||
|
n := strings.IndexByte(h, ':')
|
||||||
|
if n < 0 {
|
||||||
|
return nil, fmt.Errorf(`missing ':' in header %q; expecting "key: value" format`, h)
|
||||||
|
}
|
||||||
|
kv := &kvs[i]
|
||||||
|
kv.key = strings.TrimSpace(h[:n])
|
||||||
|
kv.value = strings.TrimSpace(h[n+1:])
|
||||||
|
}
|
||||||
|
return kvs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertSamples(samples []prompb.Sample, labels []prompb.Label) *vm.TimeSeries {
|
||||||
|
labelPairs := make([]vm.LabelPair, 0, len(labels))
|
||||||
|
nameValue := ""
|
||||||
|
for _, label := range labels {
|
||||||
|
if label.Name == "__name__" {
|
||||||
|
nameValue = label.Value
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
labelPairs = append(labelPairs, vm.LabelPair{Name: label.Name, Value: label.Value})
|
||||||
|
}
|
||||||
|
|
||||||
|
n := len(samples)
|
||||||
|
values := make([]float64, 0, n)
|
||||||
|
timestamps := make([]int64, 0, n)
|
||||||
|
for _, sample := range samples {
|
||||||
|
values = append(values, sample.Value)
|
||||||
|
timestamps = append(timestamps, sample.Timestamp)
|
||||||
|
}
|
||||||
|
return &vm.TimeSeries{
|
||||||
|
Name: nameValue,
|
||||||
|
LabelPairs: labelPairs,
|
||||||
|
Timestamps: timestamps,
|
||||||
|
Values: values,
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,8 @@ const (
|
|||||||
StepDay string = "day"
|
StepDay string = "day"
|
||||||
// StepHour represents a one hour interval
|
// StepHour represents a one hour interval
|
||||||
StepHour string = "hour"
|
StepHour string = "hour"
|
||||||
|
// StepMinute represents a one minute interval
|
||||||
|
StepMinute string = "minute"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SplitDateRange splits start-end range in a subset of ranges respecting the given step
|
// SplitDateRange splits start-end range in a subset of ranges respecting the given step
|
||||||
@ -42,8 +44,13 @@ func SplitDateRange(start, end time.Time, step string) ([][]time.Time, error) {
|
|||||||
nextStep = func(t time.Time) (time.Time, time.Time) {
|
nextStep = func(t time.Time) (time.Time, time.Time) {
|
||||||
return t, t.Add(time.Hour * 1)
|
return t, t.Add(time.Hour * 1)
|
||||||
}
|
}
|
||||||
|
case StepMinute:
|
||||||
|
nextStep = func(t time.Time) (time.Time, time.Time) {
|
||||||
|
return t, t.Add(time.Minute * 1)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("failed to parse step value, valid values are: '%s', '%s', '%s'. provided: '%s'", StepMonth, StepDay, StepHour, step)
|
return nil, fmt.Errorf("failed to parse step value, valid values are: '%s', '%s', '%s', '%s'. provided: '%s'",
|
||||||
|
StepMonth, StepDay, StepHour, StepMinute, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentStep := start
|
currentStep := start
|
||||||
|
@ -182,6 +182,8 @@ func (im *Importer) Errors() chan *ImportError { return im.errors }
|
|||||||
// that need to be imported
|
// that need to be imported
|
||||||
func (im *Importer) Input(ts *TimeSeries) error {
|
func (im *Importer) Input(ts *TimeSeries) error {
|
||||||
select {
|
select {
|
||||||
|
case <-im.close:
|
||||||
|
return fmt.Errorf("importer is closed")
|
||||||
case im.input <- ts:
|
case im.input <- ts:
|
||||||
return nil
|
return nil
|
||||||
case err := <-im.errors:
|
case err := <-im.errors:
|
||||||
@ -197,6 +199,7 @@ func (im *Importer) Input(ts *TimeSeries) error {
|
|||||||
func (im *Importer) Close() {
|
func (im *Importer) Close() {
|
||||||
im.once.Do(func() {
|
im.once.Do(func() {
|
||||||
close(im.close)
|
close(im.close)
|
||||||
|
close(im.input)
|
||||||
im.wg.Wait()
|
im.wg.Wait()
|
||||||
close(im.errors)
|
close(im.errors)
|
||||||
})
|
})
|
||||||
@ -209,6 +212,10 @@ func (im *Importer) startWorker(bar *pb.ProgressBar, batchSize, significantFigur
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-im.close:
|
case <-im.close:
|
||||||
|
for ts := range im.input {
|
||||||
|
ts = roundTimeseriesValue(ts, significantFigures, roundDigits)
|
||||||
|
batch = append(batch, ts)
|
||||||
|
}
|
||||||
exitErr := &ImportError{
|
exitErr := &ImportError{
|
||||||
Batch: batch,
|
Batch: batch,
|
||||||
}
|
}
|
||||||
@ -217,24 +224,17 @@ func (im *Importer) startWorker(bar *pb.ProgressBar, batchSize, significantFigur
|
|||||||
}
|
}
|
||||||
im.errors <- exitErr
|
im.errors <- exitErr
|
||||||
return
|
return
|
||||||
case ts := <-im.input:
|
case ts, ok := <-im.input:
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
// init waitForBatch when first
|
// init waitForBatch when first
|
||||||
// value was received
|
// value was received
|
||||||
if waitForBatch.IsZero() {
|
if waitForBatch.IsZero() {
|
||||||
waitForBatch = time.Now()
|
waitForBatch = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
if significantFigures > 0 {
|
ts = roundTimeseriesValue(ts, significantFigures, roundDigits)
|
||||||
for i, v := range ts.Values {
|
|
||||||
ts.Values[i] = decimal.RoundToSignificantFigures(v, significantFigures)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if roundDigits < 100 {
|
|
||||||
for i, v := range ts.Values {
|
|
||||||
ts.Values[i] = decimal.RoundToDecimalDigits(v, roundDigits)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
batch = append(batch, ts)
|
batch = append(batch, ts)
|
||||||
dataPoints += len(ts.Values)
|
dataPoints += len(ts.Values)
|
||||||
|
|
||||||
@ -418,3 +418,18 @@ func byteCountSI(b int64) string {
|
|||||||
return fmt.Sprintf("%.1f %cB",
|
return fmt.Sprintf("%.1f %cB",
|
||||||
float64(b)/float64(div), "kMGTPE"[exp])
|
float64(b)/float64(div), "kMGTPE"[exp])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func roundTimeseriesValue(ts *TimeSeries, significantFigures, roundDigits int) *TimeSeries {
|
||||||
|
if significantFigures > 0 {
|
||||||
|
for i, v := range ts.Values {
|
||||||
|
ts.Values[i] = decimal.RoundToSignificantFigures(v, significantFigures)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if roundDigits < 100 {
|
||||||
|
for i, v := range ts.Values {
|
||||||
|
ts.Values[i] = decimal.RoundToDecimalDigits(v, roundDigits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
243
docs/vmctl.md
243
docs/vmctl.md
@ -11,9 +11,12 @@ vmctl provides various useful actions with VictoriaMetrics components.
|
|||||||
Features:
|
Features:
|
||||||
- migrate data from [Prometheus](#migrating-data-from-prometheus) to VictoriaMetrics using snapshot API
|
- migrate data from [Prometheus](#migrating-data-from-prometheus) to VictoriaMetrics using snapshot API
|
||||||
- migrate data from [Thanos](#migrating-data-from-thanos) to VictoriaMetrics
|
- migrate data from [Thanos](#migrating-data-from-thanos) to VictoriaMetrics
|
||||||
|
- migrate data from [Cortex](#migrating-data-from-cortex) to VictoriaMetrics
|
||||||
|
- migrate data from [Mimir](#migrating-data-from-mimir) to VictoriaMetrics
|
||||||
- migrate data from [InfluxDB](#migrating-data-from-influxdb-1x) to VictoriaMetrics
|
- migrate data from [InfluxDB](#migrating-data-from-influxdb-1x) to VictoriaMetrics
|
||||||
- migrate data from [OpenTSDB](#migrating-data-from-opentsdb) to VictoriaMetrics
|
- migrate data from [OpenTSDB](#migrating-data-from-opentsdb) to VictoriaMetrics
|
||||||
- migrate data between [VictoriaMetrics](#migrating-data-from-victoriametrics) single or cluster version.
|
- migrate data between [VictoriaMetrics](#migrating-data-from-victoriametrics) single or cluster version.
|
||||||
|
- migrate data by [Prometheus remote read protocol](#migrating-data-by-remote-read-protocol) to VictoriaMetrics
|
||||||
- [verify](#verifying-exported-blocks-from-victoriametrics) exported blocks from VictoriaMetrics single or cluster version.
|
- [verify](#verifying-exported-blocks-from-victoriametrics) exported blocks from VictoriaMetrics single or cluster version.
|
||||||
|
|
||||||
To see the full list of supported modes
|
To see the full list of supported modes
|
||||||
@ -32,6 +35,7 @@ COMMANDS:
|
|||||||
influx Migrate timeseries from InfluxDB
|
influx Migrate timeseries from InfluxDB
|
||||||
prometheus Migrate timeseries from Prometheus
|
prometheus Migrate timeseries from Prometheus
|
||||||
vm-native Migrate time series between VictoriaMetrics installations via native binary format
|
vm-native Migrate time series between VictoriaMetrics installations via native binary format
|
||||||
|
remote-read Migrate timeseries by Prometheus remote read protocol
|
||||||
verify-block Verifies correctness of data blocks exported via VictoriaMetrics Native format. See https://docs.victoriametrics.com/#how-to-export-data-in-native-format
|
verify-block Verifies correctness of data blocks exported via VictoriaMetrics Native format. See https://docs.victoriametrics.com/#how-to-export-data-in-native-format
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -436,6 +440,64 @@ Found 2 blocks to import. Continue? [Y/n] y
|
|||||||
2020/02/23 15:51:07 Total time: 7.153158218s
|
2020/02/23 15:51:07 Total time: 7.153158218s
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Migrating data by remote read protocol
|
||||||
|
|
||||||
|
`vmctl` supports the `remote-read` mode for migrating data from databases which support
|
||||||
|
[Prometheus remote read API](https://prometheus.io/docs/prometheus/latest/querying/remote_read_api/)
|
||||||
|
|
||||||
|
See `./vmctl remote-read --help` for details and full list of flags.
|
||||||
|
|
||||||
|
To start the migration process configure the following flags:
|
||||||
|
1. `--remote-read-src-addr` - data source address to read from;
|
||||||
|
2. `--vm-addr` - VictoriaMetrics address to write to. For single-node VM is usually equal to `--httpListenAddr`,
|
||||||
|
and for cluster version is equal to `--httpListenAddr` flag of vminsert component (for example `http://<vminsert>:8480/insert/<accountID>/prometheus`);
|
||||||
|
3. `--remote-read-filter-time-start` - the time filter in RFC3339 format to select time series with timestamp equal or higher than provided value. E.g. '2020-01-01T20:07:00Z';
|
||||||
|
4. `--remote-read-filter-time-end` - the time filter in RFC3339 format to select time series with timestamp equal or smaller than provided value. E.g. '2020-01-01T20:07:00Z'. Current time is used when omitted.;
|
||||||
|
5. `--remote-read-step-interval` - split export data into chunks. Valid values are `month, day, hour, minute`;
|
||||||
|
|
||||||
|
The importing process example for local installation of Prometheus
|
||||||
|
and single-node VictoriaMetrics(`http://localhost:8428`):
|
||||||
|
|
||||||
|
```
|
||||||
|
./vmctl remote-read \
|
||||||
|
--remote-read-src-addr=http://127.0.0.1:9091 \
|
||||||
|
--remote-read-filter-time-start=2021-10-18T00:00:00Z \
|
||||||
|
--remote-read-step-interval=hour \
|
||||||
|
--vm-addr=http://127.0.0.1:8428 \
|
||||||
|
--vm-concurrency=6
|
||||||
|
|
||||||
|
Split defined times into 8798 ranges to import. Continue? [Y/n]
|
||||||
|
VM worker 0:↘ 127177 samples/s
|
||||||
|
VM worker 1:↘ 140137 samples/s
|
||||||
|
VM worker 2:↘ 151606 samples/s
|
||||||
|
VM worker 3:↘ 130765 samples/s
|
||||||
|
VM worker 4:↘ 131904 samples/s
|
||||||
|
VM worker 5:↘ 132693 samples/s
|
||||||
|
Processing ranges: 8798 / 8798 [█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████] 100.00%
|
||||||
|
2022/10/19 16:45:37 Import finished!
|
||||||
|
2022/10/19 16:45:37 VictoriaMetrics importer stats:
|
||||||
|
idle duration: 6m57.793987511s;
|
||||||
|
time spent while importing: 1m18.463744801s;
|
||||||
|
total samples: 25348208;
|
||||||
|
samples/s: 323056.31;
|
||||||
|
total bytes: 669.7 MB;
|
||||||
|
bytes/s: 8.5 MB;
|
||||||
|
import requests: 127;
|
||||||
|
import requests retries: 0;
|
||||||
|
2022/10/19 16:45:37 Total time: 1m19.406283424s
|
||||||
|
```
|
||||||
|
|
||||||
|
### Filtering
|
||||||
|
|
||||||
|
The filtering consists of two parts: by labels and time.
|
||||||
|
|
||||||
|
Filtering by time can be configured via flags `--remote-read-filter-time-start` and `--remote-read-filter-time-end`
|
||||||
|
in RFC3339 format.
|
||||||
|
|
||||||
|
Filtering by labels can be configured via flags `--remote-read-filter-label` and `--remote-read-filter-label-value`.
|
||||||
|
For example, `--remote-read-filter-label=tenant` and `--remote-read-filter-label-value="team-eu"` will select only series
|
||||||
|
with `tenant="team-eu"` label-value pair.
|
||||||
|
|
||||||
## Migrating data from Thanos
|
## Migrating data from Thanos
|
||||||
|
|
||||||
Thanos uses the same storage engine as Prometheus and the data layout on-disk should be the same. That means
|
Thanos uses the same storage engine as Prometheus and the data layout on-disk should be the same. That means
|
||||||
@ -482,6 +544,187 @@ then import it into VM using `vmctl` in `prometheus` mode.
|
|||||||
vmctl prometheus --prom-snapshot thanos-data --vm-addr http://victoria-metrics:8428
|
vmctl prometheus --prom-snapshot thanos-data --vm-addr http://victoria-metrics:8428
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Remote read protocol
|
||||||
|
|
||||||
|
Currently, Thanos doesn't support streaming remote read protocol. It is [recommended](https://thanos.io/tip/thanos/integrations.md/#storeapi-as-prometheus-remote-read)
|
||||||
|
to use [thanos-remote-read](https://github.com/G-Research/thanos-remote-read) a proxy, that allows exposing any Thanos
|
||||||
|
service (or anything that exposes gRPC StoreAPI e.g. Querier) via Prometheus remote read protocol.
|
||||||
|
|
||||||
|
If you want to migrate data, you should run [thanos-remote-read](https://github.com/G-Research/thanos-remote-read) proxy
|
||||||
|
and define the Thanos store address `./thanos-remote-read -store 127.0.0.1:19194`.
|
||||||
|
It is important to know that `store` flag is Thanos Store API gRPC endpoint.
|
||||||
|
Also, it is important to know that thanos-remote-read proxy doesn't support `STREAMED_XOR_CHUNKS` mode.
|
||||||
|
When you run thanos-remote-read proxy, it exposes port to serve HTTP on `10080 by default`.
|
||||||
|
|
||||||
|
The importing process example for local installation of Thanos
|
||||||
|
and single-node VictoriaMetrics(`http://localhost:8428`):
|
||||||
|
|
||||||
|
```
|
||||||
|
./vmctl remote-read \
|
||||||
|
--remote-read-src-addr=http://127.0.0.1:10080 \
|
||||||
|
--remote-read-filter-time-start=2021-10-18T00:00:00Z \
|
||||||
|
--remote-read-step-interval=hour \
|
||||||
|
--vm-addr=http://127.0.0.1:8428 \
|
||||||
|
--vm-concurrency=6
|
||||||
|
```
|
||||||
|
|
||||||
|
On the [thanos-remote-read](https://github.com/G-Research/thanos-remote-read) proxy side you will see logs like:
|
||||||
|
```
|
||||||
|
ts=2022-10-19T15:05:04.193916Z caller=main.go:278 level=info traceID=00000000000000000000000000000000 msg="thanos request" request="min_time:1666180800000 max_time:1666184399999 matchers:<type:RE value:\".*\" > aggregates:RAW "
|
||||||
|
ts=2022-10-19T15:05:04.468852Z caller=main.go:278 level=info traceID=00000000000000000000000000000000 msg="thanos request" request="min_time:1666184400000 max_time:1666187999999 matchers:<type:RE value:\".*\" > aggregates:RAW "
|
||||||
|
ts=2022-10-19T15:05:04.553914Z caller=main.go:278 level=info traceID=00000000000000000000000000000000 msg="thanos request" request="min_time:1666188000000 max_time:1666191364863 matchers:<type:RE value:\".*\" > aggregates:RAW "
|
||||||
|
```
|
||||||
|
|
||||||
|
And when process will finish you will see:
|
||||||
|
```
|
||||||
|
Split defined times into 8799 ranges to import. Continue? [Y/n]
|
||||||
|
VM worker 0:↓ 98183 samples/s
|
||||||
|
VM worker 1:↓ 114640 samples/s
|
||||||
|
VM worker 2:↓ 131710 samples/s
|
||||||
|
VM worker 3:↓ 114256 samples/s
|
||||||
|
VM worker 4:↓ 105671 samples/s
|
||||||
|
VM worker 5:↓ 124000 samples/s
|
||||||
|
Processing ranges: 8799 / 8799 [█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████] 100.00%
|
||||||
|
2022/10/19 18:05:07 Import finished!
|
||||||
|
2022/10/19 18:05:07 VictoriaMetrics importer stats:
|
||||||
|
idle duration: 52m13.987637229s;
|
||||||
|
time spent while importing: 9m1.728983776s;
|
||||||
|
total samples: 70836111;
|
||||||
|
samples/s: 130759.32;
|
||||||
|
total bytes: 2.2 GB;
|
||||||
|
bytes/s: 4.0 MB;
|
||||||
|
import requests: 356;
|
||||||
|
import requests retries: 0;
|
||||||
|
2022/10/19 18:05:07 Total time: 9m2.607521618s
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migrating data from Cortex
|
||||||
|
|
||||||
|
Cortex has an implementation of the Prometheus remote read protocol. That means
|
||||||
|
`vmctl` in mode `remote-read` may also be used for Cortex historical data migration.
|
||||||
|
These instructions may vary based on the details of your Cortex configuration.
|
||||||
|
Please read carefully and verify as you go.
|
||||||
|
|
||||||
|
### Remote read protocol
|
||||||
|
|
||||||
|
If you want to migrate data, you should check your cortex configuration in the section
|
||||||
|
```yaml
|
||||||
|
api:
|
||||||
|
prometheus_http_prefix:
|
||||||
|
```
|
||||||
|
|
||||||
|
If you defined some prometheus prefix, you should use it when you define flag `--remote-read-src-addr=http://127.0.0.1:9009/{prometheus_http_prefix}`.
|
||||||
|
By default, Cortex uses the `prometheus` path prefix, so you should define the flag `--remote-read-src-addr=http://127.0.0.1:9009/prometheus`.
|
||||||
|
|
||||||
|
It is important to know that Cortex doesn't support the `STREAMED_XOR_CHUNKS` mode.
|
||||||
|
When you run Cortex, it exposes a port to serve HTTP on `9009 by default`.
|
||||||
|
|
||||||
|
The importing process example for the local installation of Cortex
|
||||||
|
and single-node VictoriaMetrics(`http://localhost:8428`):
|
||||||
|
|
||||||
|
```
|
||||||
|
./vmctl remote-read \
|
||||||
|
--remote-read-src-addr=http://127.0.0.1:9009/prometheus \
|
||||||
|
--remote-read-filter-time-start=2021-10-18T00:00:00Z \
|
||||||
|
--remote-read-step-interval=hour \
|
||||||
|
--remote-read-src-check-alive=false \
|
||||||
|
--vm-addr=http://127.0.0.1:8428 \
|
||||||
|
--vm-concurrency=6
|
||||||
|
```
|
||||||
|
And when the process finishes, you will see the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
Split defined times into 8842 ranges to import. Continue? [Y/n]
|
||||||
|
VM worker 0:↗ 3863 samples/s
|
||||||
|
VM worker 1:↗ 2686 samples/s
|
||||||
|
VM worker 2:↗ 2620 samples/s
|
||||||
|
VM worker 3:↗ 2705 samples/s
|
||||||
|
VM worker 4:↗ 2643 samples/s
|
||||||
|
VM worker 5:↗ 2593 samples/s
|
||||||
|
Processing ranges: 8842 / 8842 [█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████] 100.00%
|
||||||
|
2022/10/21 12:09:49 Import finished!
|
||||||
|
2022/10/21 12:09:49 VictoriaMetrics importer stats:
|
||||||
|
idle duration: 0s;
|
||||||
|
time spent while importing: 3.82640757s;
|
||||||
|
total samples: 160232;
|
||||||
|
samples/s: 41875.31;
|
||||||
|
total bytes: 11.3 MB;
|
||||||
|
bytes/s: 3.0 MB;
|
||||||
|
import requests: 6;
|
||||||
|
import requests retries: 0;
|
||||||
|
2022/10/21 12:09:49 Total time: 4.71824253s
|
||||||
|
```
|
||||||
|
It is important to know that if you run your Cortex installation in multi-tenant mode, remote read protocol
|
||||||
|
requires an Authentication header like `X-Scope-OrgID`. You can define it via the flag `--remote-read-headers=X-Scope-OrgID:demo`
|
||||||
|
|
||||||
|
## Migrating data from Mimir
|
||||||
|
|
||||||
|
Mimir has similar implemintation as Cortex and also support of the Prometheus remote read protocol. That means
|
||||||
|
`vmctl` in mode `remote-read` may also be used for Mimir historical data migration.
|
||||||
|
These instructions may vary based on the details of your Mimir configuration.
|
||||||
|
Please read carefully and verify as you go.
|
||||||
|
|
||||||
|
### Remote read protocol
|
||||||
|
|
||||||
|
If you want to migrate data, you should check your Mimir configuration in the section
|
||||||
|
```yaml
|
||||||
|
api:
|
||||||
|
prometheus_http_prefix:
|
||||||
|
```
|
||||||
|
|
||||||
|
If you defined some prometheus prefix, you should use it when you define flag `--remote-read-src-addr=http://127.0.0.1:9009/{prometheus_http_prefix}`.
|
||||||
|
By default, Mimir uses the `prometheus` path prefix, so you should define the flag `--remote-read-src-addr=http://127.0.0.1:9009/prometheus`.
|
||||||
|
|
||||||
|
Mimir supports both remote read mode, so you can use `STREAMED_XOR_CHUNKS` mode and `SAMPLES` mode.
|
||||||
|
When you run Mimir, it exposes a port to serve HTTP on `8080 by default`.
|
||||||
|
|
||||||
|
Next example of the local installation was in multi-tenant mode (3 instances of mimir) with nginx as load balancer.
|
||||||
|
Load balancer expose single port `:9090`.
|
||||||
|
|
||||||
|
As you can see in the example we call `:9009` instead of `:8080` because of proxy.
|
||||||
|
|
||||||
|
The importing process example for the local installation of Mimir
|
||||||
|
and single-node VictoriaMetrics(`http://localhost:8428`):
|
||||||
|
|
||||||
|
```
|
||||||
|
./vmctl remote-read
|
||||||
|
--remote-read-src-addr=http://127.0.0.1:9009/prometheus \
|
||||||
|
--remote-read-filter-time-start=2021-10-18T00:00:00Z \
|
||||||
|
--remote-read-step-interval=hour \
|
||||||
|
--remote-read-src-check-alive=false \
|
||||||
|
--remote-read-headers=X-Scope-OrgID:demo \
|
||||||
|
--remote-read-use-stream=true \
|
||||||
|
--vm-addr=http://127.0.0.1:8428 \
|
||||||
|
--vm-concurrency=6
|
||||||
|
```
|
||||||
|
|
||||||
|
And when the process finishes, you will see the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
Split defined times into 8847 ranges to import. Continue? [Y/n]
|
||||||
|
VM worker 0:→ 12176 samples/s
|
||||||
|
VM worker 1:→ 11918 samples/s
|
||||||
|
VM worker 2:→ 11261 samples/s
|
||||||
|
VM worker 3:→ 12861 samples/s
|
||||||
|
VM worker 4:→ 11096 samples/s
|
||||||
|
VM worker 5:→ 11575 samples/s
|
||||||
|
Processing ranges: 8847 / 8847 [█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████] 100.00%
|
||||||
|
2022/10/21 17:22:23 Import finished!
|
||||||
|
2022/10/21 17:22:23 VictoriaMetrics importer stats:
|
||||||
|
idle duration: 0s;
|
||||||
|
time spent while importing: 15.379614356s;
|
||||||
|
total samples: 81243;
|
||||||
|
samples/s: 5282.51;
|
||||||
|
total bytes: 6.1 MB;
|
||||||
|
bytes/s: 397.8 kB;
|
||||||
|
import requests: 6;
|
||||||
|
import requests retries: 0;
|
||||||
|
2022/10/21 17:22:23 Total time: 16.287405248s
|
||||||
|
```
|
||||||
|
|
||||||
|
It is important to know that if you run your Mimir installation in multi-tenant mode, remote read protocol
|
||||||
|
requires an Authentication header like `X-Scope-OrgID`. You can define it via the flag `--remote-read-headers=X-Scope-OrgID:demo`
|
||||||
|
|
||||||
## Migrating data from VictoriaMetrics
|
## Migrating data from VictoriaMetrics
|
||||||
|
|
||||||
### Native protocol
|
### Native protocol
|
||||||
|
28
go.mod
28
go.mod
@ -23,7 +23,7 @@ require (
|
|||||||
github.com/googleapis/gax-go/v2 v2.7.0
|
github.com/googleapis/gax-go/v2 v2.7.0
|
||||||
github.com/influxdata/influxdb v1.10.0
|
github.com/influxdata/influxdb v1.10.0
|
||||||
github.com/klauspost/compress v1.15.12
|
github.com/klauspost/compress v1.15.12
|
||||||
github.com/prometheus/prometheus v1.8.2-0.20201119142752-3ad25a6dc3d9
|
github.com/prometheus/prometheus v0.39.1
|
||||||
github.com/urfave/cli/v2 v2.23.5
|
github.com/urfave/cli/v2 v2.23.5
|
||||||
github.com/valyala/fastjson v1.6.3
|
github.com/valyala/fastjson v1.6.3
|
||||||
github.com/valyala/fastrand v1.1.0
|
github.com/valyala/fastrand v1.1.0
|
||||||
@ -37,6 +37,8 @@ require (
|
|||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require github.com/gogo/protobuf v1.3.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.107.0 // indirect
|
cloud.google.com/go v0.107.0 // indirect
|
||||||
cloud.google.com/go/compute v1.12.1 // indirect
|
cloud.google.com/go/compute v1.12.1 // indirect
|
||||||
@ -44,6 +46,8 @@ require (
|
|||||||
cloud.google.com/go/iam v0.7.0 // indirect
|
cloud.google.com/go/iam v0.7.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1 // indirect
|
||||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||||
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||||
|
github.com/aws/aws-sdk-go v1.44.102 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.3 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
|
||||||
@ -61,39 +65,57 @@ require (
|
|||||||
github.com/aws/smithy-go v1.13.4 // indirect
|
github.com/aws/smithy-go v1.13.4 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/dennwc/varint v1.0.0 // indirect
|
||||||
github.com/fatih/color v1.13.0 // indirect
|
github.com/fatih/color v1.13.0 // indirect
|
||||||
github.com/go-kit/kit v0.12.0 // indirect
|
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||||
github.com/go-kit/log v0.2.1 // indirect
|
github.com/go-kit/log v0.2.1 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||||
|
github.com/go-logr/logr v1.2.3 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
|
||||||
|
github.com/grafana/regexp v0.0.0-20221005092906-f072a00f63e9 // indirect
|
||||||
|
github.com/hashicorp/go-hclog v0.16.2 // indirect
|
||||||
|
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
github.com/jpillora/backoff v1.0.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||||
github.com/oklog/ulid v1.3.1 // indirect
|
github.com/oklog/ulid v1.3.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||||
github.com/prometheus/client_model v0.3.0 // indirect
|
github.com/prometheus/client_model v0.3.0 // indirect
|
||||||
github.com/prometheus/common v0.37.0 // indirect
|
github.com/prometheus/common v0.37.0 // indirect
|
||||||
|
github.com/prometheus/common/sigv4 v0.1.0 // indirect
|
||||||
github.com/prometheus/procfs v0.8.0 // indirect
|
github.com/prometheus/procfs v0.8.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.3 // indirect
|
github.com/rivo/uniseg v0.4.3 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/stretchr/testify v1.8.1 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/histogram v1.2.0 // indirect
|
github.com/valyala/histogram v1.2.0 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.3 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.11.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/metric v0.32.3 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.11.0 // indirect
|
||||||
go.uber.org/atomic v1.10.0 // indirect
|
go.uber.org/atomic v1.10.0 // indirect
|
||||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 // indirect
|
go.uber.org/goleak v1.2.0 // indirect
|
||||||
golang.org/x/sync v0.1.0 // indirect
|
golang.org/x/sync v0.1.0 // indirect
|
||||||
golang.org/x/text v0.4.0 // indirect
|
golang.org/x/text v0.4.0 // indirect
|
||||||
|
golang.org/x/time v0.1.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
|
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
|
||||||
google.golang.org/grpc v1.51.0 // indirect
|
google.golang.org/grpc v1.51.0 // indirect
|
||||||
google.golang.org/protobuf v1.28.1 // indirect
|
google.golang.org/protobuf v1.28.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
19
vendor/github.com/alecthomas/units/COPYING
generated
vendored
Normal file
19
vendor/github.com/alecthomas/units/COPYING
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (C) 2014 Alec Thomas
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
13
vendor/github.com/alecthomas/units/README.md
generated
vendored
Normal file
13
vendor/github.com/alecthomas/units/README.md
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[![Go Reference](https://pkg.go.dev/badge/github.com/alecthomas/units.svg)](https://pkg.go.dev/github.com/alecthomas/units)
|
||||||
|
|
||||||
|
# Units - Helpful unit multipliers and functions for Go
|
||||||
|
|
||||||
|
The goal of this package is to have functionality similar to the [time](http://golang.org/pkg/time/) package.
|
||||||
|
|
||||||
|
It allows for code like this:
|
||||||
|
|
||||||
|
```go
|
||||||
|
n, err := ParseBase2Bytes("1KB")
|
||||||
|
// n == 1024
|
||||||
|
n = units.Mebibyte * 512
|
||||||
|
```
|
209
vendor/github.com/alecthomas/units/bytes.go
generated
vendored
Normal file
209
vendor/github.com/alecthomas/units/bytes.go
generated
vendored
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
package units
|
||||||
|
|
||||||
|
// Base2Bytes is the old non-SI power-of-2 byte scale (1024 bytes in a kilobyte,
|
||||||
|
// etc.).
|
||||||
|
type Base2Bytes int64
|
||||||
|
|
||||||
|
// Base-2 byte units.
|
||||||
|
const (
|
||||||
|
Kibibyte Base2Bytes = 1024
|
||||||
|
KiB = Kibibyte
|
||||||
|
Mebibyte = Kibibyte * 1024
|
||||||
|
MiB = Mebibyte
|
||||||
|
Gibibyte = Mebibyte * 1024
|
||||||
|
GiB = Gibibyte
|
||||||
|
Tebibyte = Gibibyte * 1024
|
||||||
|
TiB = Tebibyte
|
||||||
|
Pebibyte = Tebibyte * 1024
|
||||||
|
PiB = Pebibyte
|
||||||
|
Exbibyte = Pebibyte * 1024
|
||||||
|
EiB = Exbibyte
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
bytesUnitMap = MakeUnitMap("iB", "B", 1024)
|
||||||
|
oldBytesUnitMap = MakeUnitMap("B", "B", 1024)
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseBase2Bytes supports both iB and B in base-2 multipliers. That is, KB
|
||||||
|
// and KiB are both 1024.
|
||||||
|
// However "kB", which is the correct SI spelling of 1000 Bytes, is rejected.
|
||||||
|
func ParseBase2Bytes(s string) (Base2Bytes, error) {
|
||||||
|
n, err := ParseUnit(s, bytesUnitMap)
|
||||||
|
if err != nil {
|
||||||
|
n, err = ParseUnit(s, oldBytesUnitMap)
|
||||||
|
}
|
||||||
|
return Base2Bytes(n), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Base2Bytes) String() string {
|
||||||
|
return ToString(int64(b), 1024, "iB", "B")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implement encoding.TextMarshaler to process json/yaml.
|
||||||
|
func (b Base2Bytes) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(b.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implement encoding.TextUnmarshaler to process json/yaml.
|
||||||
|
func (b *Base2Bytes) UnmarshalText(text []byte) error {
|
||||||
|
n, err := ParseBase2Bytes(string(text))
|
||||||
|
*b = n
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Floor returns Base2Bytes with all but the largest unit zeroed out. So that e.g. 1GiB1MiB1KiB → 1GiB.
|
||||||
|
func (b Base2Bytes) Floor() Base2Bytes {
|
||||||
|
switch {
|
||||||
|
case b > Exbibyte:
|
||||||
|
return (b / Exbibyte) * Exbibyte
|
||||||
|
case b > Pebibyte:
|
||||||
|
return (b / Pebibyte) * Pebibyte
|
||||||
|
case b > Tebibyte:
|
||||||
|
return (b / Tebibyte) * Tebibyte
|
||||||
|
case b > Gibibyte:
|
||||||
|
return (b / Gibibyte) * Gibibyte
|
||||||
|
case b > Mebibyte:
|
||||||
|
return (b / Mebibyte) * Mebibyte
|
||||||
|
case b > Kibibyte:
|
||||||
|
return (b / Kibibyte) * Kibibyte
|
||||||
|
default:
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round returns Base2Bytes with all but the first n units zeroed out. So that e.g. 1GiB1MiB1KiB → 1GiB1MiB, if n is 2.
|
||||||
|
func (b Base2Bytes) Round(n int) Base2Bytes {
|
||||||
|
idx := 0
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case b > Exbibyte:
|
||||||
|
idx = n
|
||||||
|
case b > Pebibyte:
|
||||||
|
idx = n + 1
|
||||||
|
case b > Tebibyte:
|
||||||
|
idx = n + 2
|
||||||
|
case b > Gibibyte:
|
||||||
|
idx = n + 3
|
||||||
|
case b > Mebibyte:
|
||||||
|
idx = n + 4
|
||||||
|
case b > Kibibyte:
|
||||||
|
idx = n + 5
|
||||||
|
}
|
||||||
|
|
||||||
|
switch idx {
|
||||||
|
case 1:
|
||||||
|
return b - b%Exbibyte
|
||||||
|
case 2:
|
||||||
|
return b - b%Pebibyte
|
||||||
|
case 3:
|
||||||
|
return b - b%Tebibyte
|
||||||
|
case 4:
|
||||||
|
return b - b%Gibibyte
|
||||||
|
case 5:
|
||||||
|
return b - b%Mebibyte
|
||||||
|
case 6:
|
||||||
|
return b - b%Kibibyte
|
||||||
|
default:
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var metricBytesUnitMap = MakeUnitMap("B", "B", 1000)
|
||||||
|
|
||||||
|
// MetricBytes are SI byte units (1000 bytes in a kilobyte).
|
||||||
|
type MetricBytes SI
|
||||||
|
|
||||||
|
// SI base-10 byte units.
|
||||||
|
const (
|
||||||
|
Kilobyte MetricBytes = 1000
|
||||||
|
KB = Kilobyte
|
||||||
|
Megabyte = Kilobyte * 1000
|
||||||
|
MB = Megabyte
|
||||||
|
Gigabyte = Megabyte * 1000
|
||||||
|
GB = Gigabyte
|
||||||
|
Terabyte = Gigabyte * 1000
|
||||||
|
TB = Terabyte
|
||||||
|
Petabyte = Terabyte * 1000
|
||||||
|
PB = Petabyte
|
||||||
|
Exabyte = Petabyte * 1000
|
||||||
|
EB = Exabyte
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseMetricBytes parses base-10 metric byte units. That is, KB is 1000 bytes.
|
||||||
|
func ParseMetricBytes(s string) (MetricBytes, error) {
|
||||||
|
n, err := ParseUnit(s, metricBytesUnitMap)
|
||||||
|
return MetricBytes(n), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: represents 1000B as uppercase "KB", while SI standard requires "kB".
|
||||||
|
func (m MetricBytes) String() string {
|
||||||
|
return ToString(int64(m), 1000, "B", "B")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Floor returns MetricBytes with all but the largest unit zeroed out. So that e.g. 1GB1MB1KB → 1GB.
|
||||||
|
func (b MetricBytes) Floor() MetricBytes {
|
||||||
|
switch {
|
||||||
|
case b > Exabyte:
|
||||||
|
return (b / Exabyte) * Exabyte
|
||||||
|
case b > Petabyte:
|
||||||
|
return (b / Petabyte) * Petabyte
|
||||||
|
case b > Terabyte:
|
||||||
|
return (b / Terabyte) * Terabyte
|
||||||
|
case b > Gigabyte:
|
||||||
|
return (b / Gigabyte) * Gigabyte
|
||||||
|
case b > Megabyte:
|
||||||
|
return (b / Megabyte) * Megabyte
|
||||||
|
case b > Kilobyte:
|
||||||
|
return (b / Kilobyte) * Kilobyte
|
||||||
|
default:
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round returns MetricBytes with all but the first n units zeroed out. So that e.g. 1GB1MB1KB → 1GB1MB, if n is 2.
|
||||||
|
func (b MetricBytes) Round(n int) MetricBytes {
|
||||||
|
idx := 0
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case b > Exabyte:
|
||||||
|
idx = n
|
||||||
|
case b > Petabyte:
|
||||||
|
idx = n + 1
|
||||||
|
case b > Terabyte:
|
||||||
|
idx = n + 2
|
||||||
|
case b > Gigabyte:
|
||||||
|
idx = n + 3
|
||||||
|
case b > Megabyte:
|
||||||
|
idx = n + 4
|
||||||
|
case b > Kilobyte:
|
||||||
|
idx = n + 5
|
||||||
|
}
|
||||||
|
|
||||||
|
switch idx {
|
||||||
|
case 1:
|
||||||
|
return b - b%Exabyte
|
||||||
|
case 2:
|
||||||
|
return b - b%Petabyte
|
||||||
|
case 3:
|
||||||
|
return b - b%Terabyte
|
||||||
|
case 4:
|
||||||
|
return b - b%Gigabyte
|
||||||
|
case 5:
|
||||||
|
return b - b%Megabyte
|
||||||
|
case 6:
|
||||||
|
return b - b%Kilobyte
|
||||||
|
default:
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseStrictBytes supports both iB and B suffixes for base 2 and metric,
|
||||||
|
// respectively. That is, KiB represents 1024 and kB, KB represent 1000.
|
||||||
|
func ParseStrictBytes(s string) (int64, error) {
|
||||||
|
n, err := ParseUnit(s, bytesUnitMap)
|
||||||
|
if err != nil {
|
||||||
|
n, err = ParseUnit(s, metricBytesUnitMap)
|
||||||
|
}
|
||||||
|
return int64(n), err
|
||||||
|
}
|
13
vendor/github.com/alecthomas/units/doc.go
generated
vendored
Normal file
13
vendor/github.com/alecthomas/units/doc.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Package units provides helpful unit multipliers and functions for Go.
|
||||||
|
//
|
||||||
|
// The goal of this package is to have functionality similar to the time [1] package.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// [1] http://golang.org/pkg/time/
|
||||||
|
//
|
||||||
|
// It allows for code like this:
|
||||||
|
//
|
||||||
|
// n, err := ParseBase2Bytes("1KB")
|
||||||
|
// // n == 1024
|
||||||
|
// n = units.Mebibyte * 512
|
||||||
|
package units
|
50
vendor/github.com/alecthomas/units/si.go
generated
vendored
Normal file
50
vendor/github.com/alecthomas/units/si.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package units
|
||||||
|
|
||||||
|
// SI units.
|
||||||
|
type SI int64
|
||||||
|
|
||||||
|
// SI unit multiples.
|
||||||
|
const (
|
||||||
|
Kilo SI = 1000
|
||||||
|
Mega = Kilo * 1000
|
||||||
|
Giga = Mega * 1000
|
||||||
|
Tera = Giga * 1000
|
||||||
|
Peta = Tera * 1000
|
||||||
|
Exa = Peta * 1000
|
||||||
|
)
|
||||||
|
|
||||||
|
func MakeUnitMap(suffix, shortSuffix string, scale int64) map[string]float64 {
|
||||||
|
res := map[string]float64{
|
||||||
|
shortSuffix: 1,
|
||||||
|
// see below for "k" / "K"
|
||||||
|
"M" + suffix: float64(scale * scale),
|
||||||
|
"G" + suffix: float64(scale * scale * scale),
|
||||||
|
"T" + suffix: float64(scale * scale * scale * scale),
|
||||||
|
"P" + suffix: float64(scale * scale * scale * scale * scale),
|
||||||
|
"E" + suffix: float64(scale * scale * scale * scale * scale * scale),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard SI prefixes use lowercase "k" for kilo = 1000.
|
||||||
|
// For compatibility, and to be fool-proof, we accept both "k" and "K" in metric mode.
|
||||||
|
//
|
||||||
|
// However, official binary prefixes are always capitalized - "KiB" -
|
||||||
|
// and we specifically never parse "kB" as 1024B because:
|
||||||
|
//
|
||||||
|
// (1) people pedantic enough to use lowercase according to SI unlikely to abuse "k" to mean 1024 :-)
|
||||||
|
//
|
||||||
|
// (2) Use of capital K for 1024 was an informal tradition predating IEC prefixes:
|
||||||
|
// "The binary meaning of the kilobyte for 1024 bytes typically uses the symbol KB, with an
|
||||||
|
// uppercase letter K."
|
||||||
|
// -- https://en.wikipedia.org/wiki/Kilobyte#Base_2_(1024_bytes)
|
||||||
|
// "Capitalization of the letter K became the de facto standard for binary notation, although this
|
||||||
|
// could not be extended to higher powers, and use of the lowercase k did persist.[13][14][15]"
|
||||||
|
// -- https://en.wikipedia.org/wiki/Binary_prefix#History
|
||||||
|
// See also the extensive https://en.wikipedia.org/wiki/Timeline_of_binary_prefixes.
|
||||||
|
if scale == 1024 {
|
||||||
|
res["K"+suffix] = float64(scale)
|
||||||
|
} else {
|
||||||
|
res["k"+suffix] = float64(scale)
|
||||||
|
res["K"+suffix] = float64(scale)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
138
vendor/github.com/alecthomas/units/util.go
generated
vendored
Normal file
138
vendor/github.com/alecthomas/units/util.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package units
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
siUnits = []string{"", "K", "M", "G", "T", "P", "E"}
|
||||||
|
)
|
||||||
|
|
||||||
|
func ToString(n int64, scale int64, suffix, baseSuffix string) string {
|
||||||
|
mn := len(siUnits)
|
||||||
|
out := make([]string, mn)
|
||||||
|
for i, m := range siUnits {
|
||||||
|
if n%scale != 0 || i == 0 && n == 0 {
|
||||||
|
s := suffix
|
||||||
|
if i == 0 {
|
||||||
|
s = baseSuffix
|
||||||
|
}
|
||||||
|
out[mn-1-i] = fmt.Sprintf("%d%s%s", n%scale, m, s)
|
||||||
|
}
|
||||||
|
n /= scale
|
||||||
|
if n == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(out, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Below code ripped straight from http://golang.org/src/pkg/time/format.go?s=33392:33438#L1123
|
||||||
|
var errLeadingInt = errors.New("units: bad [0-9]*") // never printed
|
||||||
|
|
||||||
|
// leadingInt consumes the leading [0-9]* from s.
|
||||||
|
func leadingInt(s string) (x int64, rem string, err error) {
|
||||||
|
i := 0
|
||||||
|
for ; i < len(s); i++ {
|
||||||
|
c := s[i]
|
||||||
|
if c < '0' || c > '9' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if x >= (1<<63-10)/10 {
|
||||||
|
// overflow
|
||||||
|
return 0, "", errLeadingInt
|
||||||
|
}
|
||||||
|
x = x*10 + int64(c) - '0'
|
||||||
|
}
|
||||||
|
return x, s[i:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseUnit(s string, unitMap map[string]float64) (int64, error) {
|
||||||
|
// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
|
||||||
|
orig := s
|
||||||
|
f := float64(0)
|
||||||
|
neg := false
|
||||||
|
|
||||||
|
// Consume [-+]?
|
||||||
|
if s != "" {
|
||||||
|
c := s[0]
|
||||||
|
if c == '-' || c == '+' {
|
||||||
|
neg = c == '-'
|
||||||
|
s = s[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Special case: if all that is left is "0", this is zero.
|
||||||
|
if s == "0" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
if s == "" {
|
||||||
|
return 0, errors.New("units: invalid " + orig)
|
||||||
|
}
|
||||||
|
for s != "" {
|
||||||
|
g := float64(0) // this element of the sequence
|
||||||
|
|
||||||
|
var x int64
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// The next character must be [0-9.]
|
||||||
|
if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) {
|
||||||
|
return 0, errors.New("units: invalid " + orig)
|
||||||
|
}
|
||||||
|
// Consume [0-9]*
|
||||||
|
pl := len(s)
|
||||||
|
x, s, err = leadingInt(s)
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.New("units: invalid " + orig)
|
||||||
|
}
|
||||||
|
g = float64(x)
|
||||||
|
pre := pl != len(s) // whether we consumed anything before a period
|
||||||
|
|
||||||
|
// Consume (\.[0-9]*)?
|
||||||
|
post := false
|
||||||
|
if s != "" && s[0] == '.' {
|
||||||
|
s = s[1:]
|
||||||
|
pl := len(s)
|
||||||
|
x, s, err = leadingInt(s)
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.New("units: invalid " + orig)
|
||||||
|
}
|
||||||
|
scale := 1.0
|
||||||
|
for n := pl - len(s); n > 0; n-- {
|
||||||
|
scale *= 10
|
||||||
|
}
|
||||||
|
g += float64(x) / scale
|
||||||
|
post = pl != len(s)
|
||||||
|
}
|
||||||
|
if !pre && !post {
|
||||||
|
// no digits (e.g. ".s" or "-.s")
|
||||||
|
return 0, errors.New("units: invalid " + orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume unit.
|
||||||
|
i := 0
|
||||||
|
for ; i < len(s); i++ {
|
||||||
|
c := s[i]
|
||||||
|
if c == '.' || ('0' <= c && c <= '9') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u := s[:i]
|
||||||
|
s = s[i:]
|
||||||
|
unit, ok := unitMap[u]
|
||||||
|
if !ok {
|
||||||
|
return 0, errors.New("units: unknown unit " + u + " in " + orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
f += g * unit
|
||||||
|
}
|
||||||
|
|
||||||
|
if neg {
|
||||||
|
f = -f
|
||||||
|
}
|
||||||
|
if f < float64(-1<<63) || f > float64(1<<63-1) {
|
||||||
|
return 0, errors.New("units: overflow parsing unit")
|
||||||
|
}
|
||||||
|
return int64(f), nil
|
||||||
|
}
|
202
vendor/github.com/aws/aws-sdk-go/LICENSE.txt
generated
vendored
Normal file
202
vendor/github.com/aws/aws-sdk-go/LICENSE.txt
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 [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
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.
|
3
vendor/github.com/aws/aws-sdk-go/NOTICE.txt
generated
vendored
Normal file
3
vendor/github.com/aws/aws-sdk-go/NOTICE.txt
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
AWS SDK for Go
|
||||||
|
Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
Copyright 2014-2015 Stripe, Inc.
|
164
vendor/github.com/aws/aws-sdk-go/aws/awserr/error.go
generated
vendored
Normal file
164
vendor/github.com/aws/aws-sdk-go/aws/awserr/error.go
generated
vendored
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// Package awserr represents API error interface accessors for the SDK.
|
||||||
|
package awserr
|
||||||
|
|
||||||
|
// An Error wraps lower level errors with code, message and an original error.
|
||||||
|
// The underlying concrete error type may also satisfy other interfaces which
|
||||||
|
// can be to used to obtain more specific information about the error.
|
||||||
|
//
|
||||||
|
// Calling Error() or String() will always include the full information about
|
||||||
|
// an error based on its underlying type.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// output, err := s3manage.Upload(svc, input, opts)
|
||||||
|
// if err != nil {
|
||||||
|
// if awsErr, ok := err.(awserr.Error); ok {
|
||||||
|
// // Get error details
|
||||||
|
// log.Println("Error:", awsErr.Code(), awsErr.Message())
|
||||||
|
//
|
||||||
|
// // Prints out full error message, including original error if there was one.
|
||||||
|
// log.Println("Error:", awsErr.Error())
|
||||||
|
//
|
||||||
|
// // Get original error
|
||||||
|
// if origErr := awsErr.OrigErr(); origErr != nil {
|
||||||
|
// // operate on original error.
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// fmt.Println(err.Error())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
type Error interface {
|
||||||
|
// Satisfy the generic error interface.
|
||||||
|
error
|
||||||
|
|
||||||
|
// Returns the short phrase depicting the classification of the error.
|
||||||
|
Code() string
|
||||||
|
|
||||||
|
// Returns the error details message.
|
||||||
|
Message() string
|
||||||
|
|
||||||
|
// Returns the original error if one was set. Nil is returned if not set.
|
||||||
|
OrigErr() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchError is a batch of errors which also wraps lower level errors with
|
||||||
|
// code, message, and original errors. Calling Error() will include all errors
|
||||||
|
// that occurred in the batch.
|
||||||
|
//
|
||||||
|
// Deprecated: Replaced with BatchedErrors. Only defined for backwards
|
||||||
|
// compatibility.
|
||||||
|
type BatchError interface {
|
||||||
|
// Satisfy the generic error interface.
|
||||||
|
error
|
||||||
|
|
||||||
|
// Returns the short phrase depicting the classification of the error.
|
||||||
|
Code() string
|
||||||
|
|
||||||
|
// Returns the error details message.
|
||||||
|
Message() string
|
||||||
|
|
||||||
|
// Returns the original error if one was set. Nil is returned if not set.
|
||||||
|
OrigErrs() []error
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchedErrors is a batch of errors which also wraps lower level errors with
|
||||||
|
// code, message, and original errors. Calling Error() will include all errors
|
||||||
|
// that occurred in the batch.
|
||||||
|
//
|
||||||
|
// Replaces BatchError
|
||||||
|
type BatchedErrors interface {
|
||||||
|
// Satisfy the base Error interface.
|
||||||
|
Error
|
||||||
|
|
||||||
|
// Returns the original error if one was set. Nil is returned if not set.
|
||||||
|
OrigErrs() []error
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns an Error object described by the code, message, and origErr.
|
||||||
|
//
|
||||||
|
// If origErr satisfies the Error interface it will not be wrapped within a new
|
||||||
|
// Error object and will instead be returned.
|
||||||
|
func New(code, message string, origErr error) Error {
|
||||||
|
var errs []error
|
||||||
|
if origErr != nil {
|
||||||
|
errs = append(errs, origErr)
|
||||||
|
}
|
||||||
|
return newBaseError(code, message, errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBatchError returns an BatchedErrors with a collection of errors as an
|
||||||
|
// array of errors.
|
||||||
|
func NewBatchError(code, message string, errs []error) BatchedErrors {
|
||||||
|
return newBaseError(code, message, errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A RequestFailure is an interface to extract request failure information from
|
||||||
|
// an Error such as the request ID of the failed request returned by a service.
|
||||||
|
// RequestFailures may not always have a requestID value if the request failed
|
||||||
|
// prior to reaching the service such as a connection error.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// output, err := s3manage.Upload(svc, input, opts)
|
||||||
|
// if err != nil {
|
||||||
|
// if reqerr, ok := err.(RequestFailure); ok {
|
||||||
|
// log.Println("Request failed", reqerr.Code(), reqerr.Message(), reqerr.RequestID())
|
||||||
|
// } else {
|
||||||
|
// log.Println("Error:", err.Error())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Combined with awserr.Error:
|
||||||
|
//
|
||||||
|
// output, err := s3manage.Upload(svc, input, opts)
|
||||||
|
// if err != nil {
|
||||||
|
// if awsErr, ok := err.(awserr.Error); ok {
|
||||||
|
// // Generic AWS Error with Code, Message, and original error (if any)
|
||||||
|
// fmt.Println(awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
|
||||||
|
//
|
||||||
|
// if reqErr, ok := err.(awserr.RequestFailure); ok {
|
||||||
|
// // A service error occurred
|
||||||
|
// fmt.Println(reqErr.StatusCode(), reqErr.RequestID())
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// fmt.Println(err.Error())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
type RequestFailure interface {
|
||||||
|
Error
|
||||||
|
|
||||||
|
// The status code of the HTTP response.
|
||||||
|
StatusCode() int
|
||||||
|
|
||||||
|
// The request ID returned by the service for a request failure. This will
|
||||||
|
// be empty if no request ID is available such as the request failed due
|
||||||
|
// to a connection error.
|
||||||
|
RequestID() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
}
|
221
vendor/github.com/aws/aws-sdk-go/aws/awserr/types.go
generated
vendored
Normal file
221
vendor/github.com/aws/aws-sdk-go/aws/awserr/types.go
generated
vendored
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
package awserr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SprintError returns a string of the formatted error code.
|
||||||
|
//
|
||||||
|
// Both extra and origErr are optional. If they are included their lines
|
||||||
|
// will be added, but if they are not included their lines will be ignored.
|
||||||
|
func SprintError(code, message, extra string, origErr error) string {
|
||||||
|
msg := fmt.Sprintf("%s: %s", code, message)
|
||||||
|
if extra != "" {
|
||||||
|
msg = fmt.Sprintf("%s\n\t%s", msg, extra)
|
||||||
|
}
|
||||||
|
if origErr != nil {
|
||||||
|
msg = fmt.Sprintf("%s\ncaused by: %s", msg, origErr.Error())
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// A baseError wraps the code and message which defines an error. It also
|
||||||
|
// can be used to wrap an original error object.
|
||||||
|
//
|
||||||
|
// Should be used as the root for errors satisfying the awserr.Error. Also
|
||||||
|
// for any error which does not fit into a specific error wrapper type.
|
||||||
|
type baseError struct {
|
||||||
|
// Classification of error
|
||||||
|
code string
|
||||||
|
|
||||||
|
// Detailed information about error
|
||||||
|
message string
|
||||||
|
|
||||||
|
// Optional original error this error is based off of. Allows building
|
||||||
|
// chained errors.
|
||||||
|
errs []error
|
||||||
|
}
|
||||||
|
|
||||||
|
// newBaseError returns an error object for the code, message, and errors.
|
||||||
|
//
|
||||||
|
// code is a short no whitespace phrase depicting the classification of
|
||||||
|
// the error that is being created.
|
||||||
|
//
|
||||||
|
// message is the free flow string containing detailed information about the
|
||||||
|
// error.
|
||||||
|
//
|
||||||
|
// origErrs is the error objects which will be nested under the new errors to
|
||||||
|
// be returned.
|
||||||
|
func newBaseError(code, message string, origErrs []error) *baseError {
|
||||||
|
b := &baseError{
|
||||||
|
code: code,
|
||||||
|
message: message,
|
||||||
|
errs: origErrs,
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns the string representation of the error.
|
||||||
|
//
|
||||||
|
// See ErrorWithExtra for formatting.
|
||||||
|
//
|
||||||
|
// Satisfies the error interface.
|
||||||
|
func (b baseError) Error() string {
|
||||||
|
size := len(b.errs)
|
||||||
|
if size > 0 {
|
||||||
|
return SprintError(b.code, b.message, "", errorList(b.errs))
|
||||||
|
}
|
||||||
|
|
||||||
|
return SprintError(b.code, b.message, "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the error.
|
||||||
|
// Alias for Error to satisfy the stringer interface.
|
||||||
|
func (b baseError) String() string {
|
||||||
|
return b.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code returns the short phrase depicting the classification of the error.
|
||||||
|
func (b baseError) Code() string {
|
||||||
|
return b.code
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message returns the error details message.
|
||||||
|
func (b baseError) Message() string {
|
||||||
|
return b.message
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrigErr returns the original error if one was set. Nil is returned if no
|
||||||
|
// error was set. This only returns the first element in the list. If the full
|
||||||
|
// list is needed, use BatchedErrors.
|
||||||
|
func (b baseError) OrigErr() error {
|
||||||
|
switch len(b.errs) {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case 1:
|
||||||
|
return b.errs[0]
|
||||||
|
default:
|
||||||
|
if err, ok := b.errs[0].(Error); ok {
|
||||||
|
return NewBatchError(err.Code(), err.Message(), b.errs[1:])
|
||||||
|
}
|
||||||
|
return NewBatchError("BatchedErrors",
|
||||||
|
"multiple errors occurred", b.errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrigErrs returns the original errors if one was set. An empty slice is
|
||||||
|
// returned if no error was set.
|
||||||
|
func (b baseError) OrigErrs() []error {
|
||||||
|
return b.errs
|
||||||
|
}
|
||||||
|
|
||||||
|
// So that the Error interface type can be included as an anonymous field
|
||||||
|
// in the requestError struct and not conflict with the error.Error() method.
|
||||||
|
type awsError Error
|
||||||
|
|
||||||
|
// A requestError wraps a request or service error.
|
||||||
|
//
|
||||||
|
// Composed of baseError for code, message, and original error.
|
||||||
|
type requestError struct {
|
||||||
|
awsError
|
||||||
|
statusCode int
|
||||||
|
requestID string
|
||||||
|
bytes []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// newRequestError 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.
|
||||||
|
//
|
||||||
|
// Also wraps original errors via the baseError.
|
||||||
|
func newRequestError(err Error, statusCode int, requestID string) *requestError {
|
||||||
|
return &requestError{
|
||||||
|
awsError: err,
|
||||||
|
statusCode: statusCode,
|
||||||
|
requestID: requestID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns the string representation of the error.
|
||||||
|
// Satisfies the error interface.
|
||||||
|
func (r requestError) Error() string {
|
||||||
|
extra := fmt.Sprintf("status code: %d, request id: %s",
|
||||||
|
r.statusCode, r.requestID)
|
||||||
|
return SprintError(r.Code(), r.Message(), extra, r.OrigErr())
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the error.
|
||||||
|
// Alias for Error to satisfy the stringer interface.
|
||||||
|
func (r requestError) String() string {
|
||||||
|
return r.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusCode returns the wrapped status code for the error
|
||||||
|
func (r requestError) StatusCode() int {
|
||||||
|
return r.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestID returns the wrapped requestID
|
||||||
|
func (r requestError) RequestID() string {
|
||||||
|
return r.requestID
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrigErrs returns the original errors if one was set. An empty slice is
|
||||||
|
// returned if no error was set.
|
||||||
|
func (r requestError) OrigErrs() []error {
|
||||||
|
if b, ok := r.awsError.(BatchedErrors); ok {
|
||||||
|
return b.OrigErrs()
|
||||||
|
}
|
||||||
|
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
|
||||||
|
|
||||||
|
// Error returns the string representation of the error.
|
||||||
|
//
|
||||||
|
// Satisfies the error interface.
|
||||||
|
func (e errorList) Error() string {
|
||||||
|
msg := ""
|
||||||
|
// How do we want to handle the array size being zero
|
||||||
|
if size := len(e); size > 0 {
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
msg += e[i].Error()
|
||||||
|
// We check the next index to see if it is within the slice.
|
||||||
|
// If it is, then we append a newline. We do this, because unit tests
|
||||||
|
// could be broken with the additional '\n'
|
||||||
|
if i+1 < size {
|
||||||
|
msg += "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
}
|
108
vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go
generated
vendored
Normal file
108
vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package awsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Copy deeply copies a src structure to dst. Useful for copying request and
|
||||||
|
// response structures.
|
||||||
|
//
|
||||||
|
// Can copy between structs of different type, but will only copy fields which
|
||||||
|
// are assignable, and exist in both structs. Fields which are not assignable,
|
||||||
|
// or do not exist in both structs are ignored.
|
||||||
|
func Copy(dst, src interface{}) {
|
||||||
|
dstval := reflect.ValueOf(dst)
|
||||||
|
if !dstval.IsValid() {
|
||||||
|
panic("Copy dst cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
rcopy(dstval, reflect.ValueOf(src), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyOf returns a copy of src while also allocating the memory for dst.
|
||||||
|
// src must be a pointer type or this operation will fail.
|
||||||
|
func CopyOf(src interface{}) (dst interface{}) {
|
||||||
|
dsti := reflect.New(reflect.TypeOf(src).Elem())
|
||||||
|
dst = dsti.Interface()
|
||||||
|
rcopy(dsti, reflect.ValueOf(src), true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// rcopy performs a recursive copy of values from the source to destination.
|
||||||
|
//
|
||||||
|
// root is used to skip certain aspects of the copy which are not valid
|
||||||
|
// for the root node of a object.
|
||||||
|
func rcopy(dst, src reflect.Value, root bool) {
|
||||||
|
if !src.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch src.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
if _, ok := src.Interface().(io.Reader); ok {
|
||||||
|
if dst.Kind() == reflect.Ptr && dst.Elem().CanSet() {
|
||||||
|
dst.Elem().Set(src)
|
||||||
|
} else if dst.CanSet() {
|
||||||
|
dst.Set(src)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e := src.Type().Elem()
|
||||||
|
if dst.CanSet() && !src.IsNil() {
|
||||||
|
if _, ok := src.Interface().(*time.Time); !ok {
|
||||||
|
dst.Set(reflect.New(e))
|
||||||
|
} else {
|
||||||
|
tempValue := reflect.New(e)
|
||||||
|
tempValue.Elem().Set(src.Elem())
|
||||||
|
// Sets time.Time's unexported values
|
||||||
|
dst.Set(tempValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if src.Elem().IsValid() {
|
||||||
|
// Keep the current root state since the depth hasn't changed
|
||||||
|
rcopy(dst.Elem(), src.Elem(), root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
t := dst.Type()
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
name := t.Field(i).Name
|
||||||
|
srcVal := src.FieldByName(name)
|
||||||
|
dstVal := dst.FieldByName(name)
|
||||||
|
if srcVal.IsValid() && dstVal.CanSet() {
|
||||||
|
rcopy(dstVal, srcVal, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
if src.IsNil() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
|
||||||
|
dst.Set(s)
|
||||||
|
for i := 0; i < src.Len(); i++ {
|
||||||
|
rcopy(dst.Index(i), src.Index(i), false)
|
||||||
|
}
|
||||||
|
case reflect.Map:
|
||||||
|
if src.IsNil() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
s := reflect.MakeMap(src.Type())
|
||||||
|
dst.Set(s)
|
||||||
|
for _, k := range src.MapKeys() {
|
||||||
|
v := src.MapIndex(k)
|
||||||
|
v2 := reflect.New(v.Type()).Elem()
|
||||||
|
rcopy(v2, v, false)
|
||||||
|
dst.SetMapIndex(k, v2)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Assign the value if possible. If its not assignable, the value would
|
||||||
|
// need to be converted and the impact of that may be unexpected, or is
|
||||||
|
// not compatible with the dst type.
|
||||||
|
if src.Type().AssignableTo(dst.Type()) {
|
||||||
|
dst.Set(src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go
generated
vendored
Normal file
27
vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package awsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeepEqual returns if the two values are deeply equal like reflect.DeepEqual.
|
||||||
|
// In addition to this, this method will also dereference the input values if
|
||||||
|
// possible so the DeepEqual performed will not fail if one parameter is a
|
||||||
|
// pointer and the other is not.
|
||||||
|
//
|
||||||
|
// DeepEqual will not perform indirection of nested values of the input parameters.
|
||||||
|
func DeepEqual(a, b interface{}) bool {
|
||||||
|
ra := reflect.Indirect(reflect.ValueOf(a))
|
||||||
|
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 they are equal
|
||||||
|
// If they are of different types they are not equal
|
||||||
|
return reflect.TypeOf(a) == reflect.TypeOf(b)
|
||||||
|
} else if raValid != rbValid {
|
||||||
|
// Both values must be valid to be equal
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflect.DeepEqual(ra.Interface(), rb.Interface())
|
||||||
|
}
|
221
vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go
generated
vendored
Normal file
221
vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go
generated
vendored
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
package awsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jmespath/go-jmespath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`)
|
||||||
|
|
||||||
|
// rValuesAtPath returns a slice of values found in value v. The values
|
||||||
|
// in v are explored recursively so all nested values are collected.
|
||||||
|
func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTerm bool) []reflect.Value {
|
||||||
|
pathparts := strings.Split(path, "||")
|
||||||
|
if len(pathparts) > 1 {
|
||||||
|
for _, pathpart := range pathparts {
|
||||||
|
vals := rValuesAtPath(v, pathpart, createPath, caseSensitive, nilTerm)
|
||||||
|
if len(vals) > 0 {
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
values := []reflect.Value{reflect.Indirect(reflect.ValueOf(v))}
|
||||||
|
components := strings.Split(path, ".")
|
||||||
|
for len(values) > 0 && len(components) > 0 {
|
||||||
|
var index *int64
|
||||||
|
var indexStar bool
|
||||||
|
c := strings.TrimSpace(components[0])
|
||||||
|
if c == "" { // no actual component, illegal syntax
|
||||||
|
return nil
|
||||||
|
} else if caseSensitive && c != "*" && strings.ToLower(c[0:1]) == c[0:1] {
|
||||||
|
// TODO normalize case for user
|
||||||
|
return nil // don't support unexported fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse this component
|
||||||
|
if m := indexRe.FindStringSubmatch(c); m != nil {
|
||||||
|
c = m[1]
|
||||||
|
if m[2] == "" {
|
||||||
|
index = nil
|
||||||
|
indexStar = true
|
||||||
|
} else {
|
||||||
|
i, _ := strconv.ParseInt(m[2], 10, 32)
|
||||||
|
index = &i
|
||||||
|
indexStar = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextvals := []reflect.Value{}
|
||||||
|
for _, value := range values {
|
||||||
|
// pull component name out of struct member
|
||||||
|
if value.Kind() != reflect.Struct {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if c == "*" { // pull all members
|
||||||
|
for i := 0; i < value.NumField(); i++ {
|
||||||
|
if f := reflect.Indirect(value.Field(i)); f.IsValid() {
|
||||||
|
nextvals = append(nextvals, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value.FieldByNameFunc(func(name string) bool {
|
||||||
|
if c == name {
|
||||||
|
return true
|
||||||
|
} else if !caseSensitive && strings.EqualFold(name, c) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
if nilTerm && value.Kind() == reflect.Ptr && len(components[1:]) == 0 {
|
||||||
|
if !value.IsNil() {
|
||||||
|
value.Set(reflect.Zero(value.Type()))
|
||||||
|
}
|
||||||
|
return []reflect.Value{value}
|
||||||
|
}
|
||||||
|
|
||||||
|
if createPath && value.Kind() == reflect.Ptr && value.IsNil() {
|
||||||
|
// TODO if the value is the terminus it should not be created
|
||||||
|
// if the value to be set to its position is nil.
|
||||||
|
value.Set(reflect.New(value.Type().Elem()))
|
||||||
|
value = value.Elem()
|
||||||
|
} else {
|
||||||
|
value = reflect.Indirect(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
|
||||||
|
if !createPath && value.IsNil() {
|
||||||
|
value = reflect.ValueOf(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.IsValid() {
|
||||||
|
nextvals = append(nextvals, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
values = nextvals
|
||||||
|
|
||||||
|
if indexStar || index != nil {
|
||||||
|
nextvals = []reflect.Value{}
|
||||||
|
for _, valItem := range values {
|
||||||
|
value := reflect.Indirect(valItem)
|
||||||
|
if value.Kind() != reflect.Slice {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if indexStar { // grab all indices
|
||||||
|
for i := 0; i < value.Len(); i++ {
|
||||||
|
idx := reflect.Indirect(value.Index(i))
|
||||||
|
if idx.IsValid() {
|
||||||
|
nextvals = append(nextvals, idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull out index
|
||||||
|
i := int(*index)
|
||||||
|
if i >= value.Len() { // check out of bounds
|
||||||
|
if createPath {
|
||||||
|
// TODO resize slice
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if i < 0 { // support negative indexing
|
||||||
|
i = value.Len() + i
|
||||||
|
}
|
||||||
|
value = reflect.Indirect(value.Index(i))
|
||||||
|
|
||||||
|
if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
|
||||||
|
if !createPath && value.IsNil() {
|
||||||
|
value = reflect.ValueOf(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.IsValid() {
|
||||||
|
nextvals = append(nextvals, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
values = nextvals
|
||||||
|
}
|
||||||
|
|
||||||
|
components = components[1:]
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValuesAtPath returns a list of values at the case insensitive lexical
|
||||||
|
// path inside of a structure.
|
||||||
|
func ValuesAtPath(i interface{}, path string) ([]interface{}, error) {
|
||||||
|
result, err := jmespath.Search(path, i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := reflect.ValueOf(result)
|
||||||
|
if !v.IsValid() || (v.Kind() == reflect.Ptr && v.IsNil()) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if s, ok := result.([]interface{}); ok {
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
if v.Kind() == reflect.Map && v.Len() == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if v.Kind() == reflect.Slice {
|
||||||
|
out := make([]interface{}, v.Len())
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
out[i] = v.Index(i).Interface()
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []interface{}{result}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValueAtPath sets a value at the case insensitive lexical path inside
|
||||||
|
// of a structure.
|
||||||
|
func SetValueAtPath(i interface{}, path string, v interface{}) {
|
||||||
|
rvals := rValuesAtPath(i, path, true, false, v == nil)
|
||||||
|
for _, rval := range rvals {
|
||||||
|
if rval.Kind() == reflect.Ptr && rval.IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
setValue(rval, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setValue(dstVal reflect.Value, src interface{}) {
|
||||||
|
if dstVal.Kind() == reflect.Ptr {
|
||||||
|
dstVal = reflect.Indirect(dstVal)
|
||||||
|
}
|
||||||
|
srcVal := reflect.ValueOf(src)
|
||||||
|
|
||||||
|
if !srcVal.IsValid() { // src is literal nil
|
||||||
|
if dstVal.CanAddr() {
|
||||||
|
// Convert to pointer so that pointer's value can be nil'ed
|
||||||
|
// dstVal = dstVal.Addr()
|
||||||
|
}
|
||||||
|
dstVal.Set(reflect.Zero(dstVal.Type()))
|
||||||
|
|
||||||
|
} else if srcVal.Kind() == reflect.Ptr {
|
||||||
|
if srcVal.IsNil() {
|
||||||
|
srcVal = reflect.Zero(dstVal.Type())
|
||||||
|
} else {
|
||||||
|
srcVal = reflect.ValueOf(src).Elem()
|
||||||
|
}
|
||||||
|
dstVal.Set(srcVal)
|
||||||
|
} else {
|
||||||
|
dstVal.Set(srcVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
123
vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go
generated
vendored
Normal file
123
vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package awsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Prettify returns the string representation of a value.
|
||||||
|
func Prettify(i interface{}) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
prettify(reflect.ValueOf(i), 0, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// prettify will recursively walk value v to build a textual
|
||||||
|
// representation of the value.
|
||||||
|
func prettify(v reflect.Value, indent int, buf *bytes.Buffer) {
|
||||||
|
for v.Kind() == reflect.Ptr {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
strtype := v.Type().String()
|
||||||
|
if strtype == "time.Time" {
|
||||||
|
fmt.Fprintf(buf, "%s", v.Interface())
|
||||||
|
break
|
||||||
|
} else if strings.HasPrefix(strtype, "io.") {
|
||||||
|
buf.WriteString("<buffer>")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
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]) {
|
||||||
|
continue // ignore unexported fields
|
||||||
|
}
|
||||||
|
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice || f.Kind() == reflect.Map) && f.IsNil() {
|
||||||
|
continue // ignore unset fields
|
||||||
|
}
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, n := range names {
|
||||||
|
val := v.FieldByName(n)
|
||||||
|
ft, ok := v.Type().FieldByName(n)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("expected to find field %v on type %v, but was not found", n, v.Type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||||
|
buf.WriteString(n + ": ")
|
||||||
|
|
||||||
|
if tag := ft.Tag.Get("sensitive"); tag == "true" {
|
||||||
|
buf.WriteString("<sensitive>")
|
||||||
|
} else {
|
||||||
|
prettify(val, indent+2, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
if i < len(names)-1 {
|
||||||
|
buf.WriteString(",\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||||
|
case reflect.Slice:
|
||||||
|
strtype := v.Type().String()
|
||||||
|
if strtype == "[]uint8" {
|
||||||
|
fmt.Fprintf(buf, "<binary> len %d", v.Len())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
nl, id, id2 := "", "", ""
|
||||||
|
if v.Len() > 3 {
|
||||||
|
nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
|
||||||
|
}
|
||||||
|
buf.WriteString("[" + nl)
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
buf.WriteString(id2)
|
||||||
|
prettify(v.Index(i), indent+2, buf)
|
||||||
|
|
||||||
|
if i < v.Len()-1 {
|
||||||
|
buf.WriteString("," + nl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString(nl + id + "]")
|
||||||
|
case reflect.Map:
|
||||||
|
buf.WriteString("{\n")
|
||||||
|
|
||||||
|
for i, k := range v.MapKeys() {
|
||||||
|
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||||
|
buf.WriteString(k.String() + ": ")
|
||||||
|
prettify(v.MapIndex(k), indent+2, buf)
|
||||||
|
|
||||||
|
if i < v.Len()-1 {
|
||||||
|
buf.WriteString(",\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||||
|
default:
|
||||||
|
if !v.IsValid() {
|
||||||
|
fmt.Fprint(buf, "<invalid value>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
format := "%v"
|
||||||
|
switch v.Interface().(type) {
|
||||||
|
case string:
|
||||||
|
format = "%q"
|
||||||
|
case io.ReadSeeker, io.Reader:
|
||||||
|
format = "buffer(%p)"
|
||||||
|
}
|
||||||
|
fmt.Fprintf(buf, format, v.Interface())
|
||||||
|
}
|
||||||
|
}
|
90
vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go
generated
vendored
Normal file
90
vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package awsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StringValue returns the string representation of a value.
|
||||||
|
//
|
||||||
|
// Deprecated: Use Prettify instead.
|
||||||
|
func StringValue(i interface{}) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
stringValue(reflect.ValueOf(i), 0, &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) {
|
||||||
|
for v.Kind() == reflect.Ptr {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
buf.WriteString("{\n")
|
||||||
|
|
||||||
|
for i := 0; i < v.Type().NumField(); i++ {
|
||||||
|
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 (fv.Kind() == reflect.Ptr || fv.Kind() == reflect.Slice) && fv.IsNil() {
|
||||||
|
continue // ignore unset fields
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||||
|
buf.WriteString(ft.Name + ": ")
|
||||||
|
|
||||||
|
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) + "}")
|
||||||
|
case reflect.Slice:
|
||||||
|
nl, id, id2 := "", "", ""
|
||||||
|
if v.Len() > 3 {
|
||||||
|
nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
|
||||||
|
}
|
||||||
|
buf.WriteString("[" + nl)
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
buf.WriteString(id2)
|
||||||
|
stringValue(v.Index(i), indent+2, buf)
|
||||||
|
|
||||||
|
if i < v.Len()-1 {
|
||||||
|
buf.WriteString("," + nl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString(nl + id + "]")
|
||||||
|
case reflect.Map:
|
||||||
|
buf.WriteString("{\n")
|
||||||
|
|
||||||
|
for i, k := range v.MapKeys() {
|
||||||
|
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||||
|
buf.WriteString(k.String() + ": ")
|
||||||
|
stringValue(v.MapIndex(k), indent+2, buf)
|
||||||
|
|
||||||
|
if i < v.Len()-1 {
|
||||||
|
buf.WriteString(",\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||||
|
default:
|
||||||
|
format := "%v"
|
||||||
|
switch v.Interface().(type) {
|
||||||
|
case string:
|
||||||
|
format = "%q"
|
||||||
|
}
|
||||||
|
fmt.Fprintf(buf, format, v.Interface())
|
||||||
|
}
|
||||||
|
}
|
94
vendor/github.com/aws/aws-sdk-go/aws/client/client.go
generated
vendored
Normal file
94
vendor/github.com/aws/aws-sdk-go/aws/client/client.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Config provides configuration to a service client instance.
|
||||||
|
type Config struct {
|
||||||
|
Config *aws.Config
|
||||||
|
Handlers request.Handlers
|
||||||
|
PartitionID string
|
||||||
|
Endpoint string
|
||||||
|
SigningRegion string
|
||||||
|
SigningName string
|
||||||
|
ResolvedRegion 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
|
||||||
|
// the ClientConfig without circular dependencies.
|
||||||
|
type ConfigProvider interface {
|
||||||
|
ClientConfig(serviceName string, cfgs ...*aws.Config) Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigNoResolveEndpointProvider same as ConfigProvider except it will not
|
||||||
|
// resolve the endpoint automatically. The service client's endpoint must be
|
||||||
|
// provided via the aws.Config.Endpoint field.
|
||||||
|
type ConfigNoResolveEndpointProvider interface {
|
||||||
|
ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Client implements the base client request and response handling
|
||||||
|
// used by all service clients.
|
||||||
|
type Client struct {
|
||||||
|
request.Retryer
|
||||||
|
metadata.ClientInfo
|
||||||
|
|
||||||
|
Config aws.Config
|
||||||
|
Handlers request.Handlers
|
||||||
|
}
|
||||||
|
|
||||||
|
// New will return a pointer to a new initialized service client.
|
||||||
|
func New(cfg aws.Config, info metadata.ClientInfo, handlers request.Handlers, options ...func(*Client)) *Client {
|
||||||
|
svc := &Client{
|
||||||
|
Config: cfg,
|
||||||
|
ClientInfo: info,
|
||||||
|
Handlers: handlers.Copy(),
|
||||||
|
}
|
||||||
|
|
||||||
|
switch retryer, ok := cfg.Retryer.(request.Retryer); {
|
||||||
|
case ok:
|
||||||
|
svc.Retryer = retryer
|
||||||
|
case cfg.Retryer != nil && cfg.Logger != nil:
|
||||||
|
s := fmt.Sprintf("WARNING: %T does not implement request.Retryer; using DefaultRetryer instead", cfg.Retryer)
|
||||||
|
cfg.Logger.Log(s)
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
maxRetries := aws.IntValue(cfg.MaxRetries)
|
||||||
|
if cfg.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries {
|
||||||
|
maxRetries = DefaultRetryerMaxNumRetries
|
||||||
|
}
|
||||||
|
svc.Retryer = DefaultRetryer{NumMaxRetries: maxRetries}
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.AddDebugHandlers()
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(svc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRequest returns a new Request pointer for the service API
|
||||||
|
// operation and parameters.
|
||||||
|
func (c *Client) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request {
|
||||||
|
return request.New(c.Config, c.ClientInfo, c.Handlers, c.Retryer, operation, params, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddDebugHandlers injects debug logging handlers into the service to log request
|
||||||
|
// debug information.
|
||||||
|
func (c *Client) AddDebugHandlers() {
|
||||||
|
c.Handlers.Send.PushFrontNamed(LogHTTPRequestHandler)
|
||||||
|
c.Handlers.Send.PushBackNamed(LogHTTPResponseHandler)
|
||||||
|
}
|
177
vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go
generated
vendored
Normal file
177
vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"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
|
||||||
|
// most services. If you want to implement custom retry logic, you can implement the
|
||||||
|
// request.Retryer interface.
|
||||||
|
//
|
||||||
|
type DefaultRetryer struct {
|
||||||
|
// Num max Retries is the number of max retries that will be performed.
|
||||||
|
// By default, this is zero.
|
||||||
|
NumMaxRetries int
|
||||||
|
|
||||||
|
// MinRetryDelay is the minimum retry delay after which retry will be performed.
|
||||||
|
// If not set, the value is 0ns.
|
||||||
|
MinRetryDelay time.Duration
|
||||||
|
|
||||||
|
// MinThrottleRetryDelay is the minimum retry delay when throttled.
|
||||||
|
// If not set, the value is 0ns.
|
||||||
|
MinThrottleDelay time.Duration
|
||||||
|
|
||||||
|
// MaxRetryDelay is the maximum retry delay before which retry must be performed.
|
||||||
|
// If not set, the value is 0ns.
|
||||||
|
MaxRetryDelay time.Duration
|
||||||
|
|
||||||
|
// MaxThrottleDelay is the maximum retry delay when throttled.
|
||||||
|
// If not set, the value is 0ns.
|
||||||
|
MaxThrottleDelay time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultRetryerMaxNumRetries sets maximum number of retries
|
||||||
|
DefaultRetryerMaxNumRetries = 3
|
||||||
|
|
||||||
|
// DefaultRetryerMinRetryDelay sets minimum retry delay
|
||||||
|
DefaultRetryerMinRetryDelay = 30 * time.Millisecond
|
||||||
|
|
||||||
|
// DefaultRetryerMinThrottleDelay sets minimum delay when throttled
|
||||||
|
DefaultRetryerMinThrottleDelay = 500 * time.Millisecond
|
||||||
|
|
||||||
|
// DefaultRetryerMaxRetryDelay sets maximum retry delay
|
||||||
|
DefaultRetryerMaxRetryDelay = 300 * time.Second
|
||||||
|
|
||||||
|
// DefaultRetryerMaxThrottleDelay sets maximum delay when throttled
|
||||||
|
DefaultRetryerMaxThrottleDelay = 300 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
// MaxRetries returns the number of maximum returns the service will use to make
|
||||||
|
// an individual API request.
|
||||||
|
func (d DefaultRetryer) MaxRetries() int {
|
||||||
|
return d.NumMaxRetries
|
||||||
|
}
|
||||||
|
|
||||||
|
// setRetryerDefaults sets the default values of the retryer if not set
|
||||||
|
func (d *DefaultRetryer) setRetryerDefaults() {
|
||||||
|
if d.MinRetryDelay == 0 {
|
||||||
|
d.MinRetryDelay = DefaultRetryerMinRetryDelay
|
||||||
|
}
|
||||||
|
if d.MaxRetryDelay == 0 {
|
||||||
|
d.MaxRetryDelay = DefaultRetryerMaxRetryDelay
|
||||||
|
}
|
||||||
|
if d.MinThrottleDelay == 0 {
|
||||||
|
d.MinThrottleDelay = DefaultRetryerMinThrottleDelay
|
||||||
|
}
|
||||||
|
if d.MaxThrottleDelay == 0 {
|
||||||
|
d.MaxThrottleDelay = DefaultRetryerMaxThrottleDelay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetryRules returns the delay duration before retrying this request again
|
||||||
|
func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
|
||||||
|
|
||||||
|
// if number of max retries is zero, no retries will be performed.
|
||||||
|
if d.NumMaxRetries == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets default value for retryer members
|
||||||
|
d.setRetryerDefaults()
|
||||||
|
|
||||||
|
// minDelay is the minimum retryer delay
|
||||||
|
minDelay := d.MinRetryDelay
|
||||||
|
|
||||||
|
var initialDelay time.Duration
|
||||||
|
|
||||||
|
isThrottle := r.IsErrorThrottle()
|
||||||
|
if isThrottle {
|
||||||
|
if delay, ok := getRetryAfterDelay(r); ok {
|
||||||
|
initialDelay = delay
|
||||||
|
}
|
||||||
|
minDelay = d.MinThrottleDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
retryCount := r.RetryCount
|
||||||
|
|
||||||
|
// maxDelay the maximum retryer delay
|
||||||
|
maxDelay := d.MaxRetryDelay
|
||||||
|
|
||||||
|
if isThrottle {
|
||||||
|
maxDelay = d.MaxThrottleDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
var delay time.Duration
|
||||||
|
|
||||||
|
// Logic to cap the retry count based on the minDelay provided
|
||||||
|
actualRetryCount := int(math.Log2(float64(minDelay))) + 1
|
||||||
|
if actualRetryCount < 63-retryCount {
|
||||||
|
delay = time.Duration(1<<uint64(retryCount)) * getJitterDelay(minDelay)
|
||||||
|
if delay > maxDelay {
|
||||||
|
delay = getJitterDelay(maxDelay / 2)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delay = getJitterDelay(maxDelay / 2)
|
||||||
|
}
|
||||||
|
return delay + initialDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
// getJitterDelay returns a jittered delay for retry
|
||||||
|
func getJitterDelay(duration time.Duration) time.Duration {
|
||||||
|
return time.Duration(sdkrand.SeededRand.Int63n(int64(duration)) + int64(duration))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldRetry returns true if the request should be retried.
|
||||||
|
func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
|
||||||
|
|
||||||
|
// ShouldRetry returns false if number of max retries is 0.
|
||||||
|
if d.NumMaxRetries == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If one of the other handlers already set the retry state
|
||||||
|
// we don't want to override it based on the service's state
|
||||||
|
if r.Retryable != nil {
|
||||||
|
return *r.Retryable
|
||||||
|
}
|
||||||
|
return r.IsErrorRetryable() || r.IsErrorThrottle()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will look in the Retry-After header, RFC 7231, for how long
|
||||||
|
// it will wait before attempting another request
|
||||||
|
func getRetryAfterDelay(r *request.Request) (time.Duration, bool) {
|
||||||
|
if !canUseRetryAfterHeader(r) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
delayStr := r.HTTPResponse.Header.Get("Retry-After")
|
||||||
|
if len(delayStr) == 0 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
delay, err := strconv.Atoi(delayStr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Duration(delay) * time.Second, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Will look at the status code to see if the retry header pertains to
|
||||||
|
// the status code.
|
||||||
|
func canUseRetryAfterHeader(r *request.Request) bool {
|
||||||
|
switch r.HTTPResponse.StatusCode {
|
||||||
|
case 429:
|
||||||
|
case 503:
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
206
vendor/github.com/aws/aws-sdk-go/aws/client/logger.go
generated
vendored
Normal file
206
vendor/github.com/aws/aws-sdk-go/aws/client/logger.go
generated
vendored
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http/httputil"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
const logReqMsg = `DEBUG: Request %s/%s Details:
|
||||||
|
---[ REQUEST POST-SIGN ]-----------------------------
|
||||||
|
%s
|
||||||
|
-----------------------------------------------------`
|
||||||
|
|
||||||
|
const logReqErrMsg = `DEBUG ERROR: Request %s/%s:
|
||||||
|
---[ REQUEST DUMP ERROR ]-----------------------------
|
||||||
|
%s
|
||||||
|
------------------------------------------------------`
|
||||||
|
|
||||||
|
type logWriter struct {
|
||||||
|
// Logger is what we will use to log the payload of a response.
|
||||||
|
Logger aws.Logger
|
||||||
|
// buf stores the contents of what has been read
|
||||||
|
buf *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *logWriter) Write(b []byte) (int, error) {
|
||||||
|
return logger.buf.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
type teeReaderCloser struct {
|
||||||
|
// io.Reader will be a tee reader that is used during logging.
|
||||||
|
// This structure will read from a body and write the contents to a logger.
|
||||||
|
io.Reader
|
||||||
|
// Source is used just to close when we are done reading.
|
||||||
|
Source io.ReadCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if !r.Config.LogLevel.AtLeast(aws.LogDebug) || r.Config.Logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||||
|
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))
|
||||||
|
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.
|
||||||
|
if err := r.Error; 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)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
if !r.Config.LogLevel.AtLeast(aws.LogDebug) || r.Config.Logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
---[ RESPONSE ]--------------------------------------
|
||||||
|
%s
|
||||||
|
-----------------------------------------------------`
|
||||||
|
|
||||||
|
const logRespErrMsg = `DEBUG ERROR: Response %s/%s:
|
||||||
|
---[ RESPONSE DUMP ERROR ]-----------------------------
|
||||||
|
%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) {
|
||||||
|
if !r.Config.LogLevel.AtLeast(aws.LogDebug) || r.Config.Logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lw := &logWriter{r.Config.Logger, bytes.NewBuffer(nil)}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
b, err := httputil.DumpResponse(req.HTTPResponse, false)
|
||||||
|
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(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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlerName = "awsdk.client.LogResponse.ResponseBody"
|
||||||
|
|
||||||
|
r.Handlers.Unmarshal.SetBackNamed(request.NamedHandler{
|
||||||
|
Name: handlerName, Fn: handlerFn,
|
||||||
|
})
|
||||||
|
r.Handlers.UnmarshalError.SetBackNamed(request.NamedHandler{
|
||||||
|
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.LogLevel.AtLeast(aws.LogDebug) || 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)))
|
||||||
|
}
|
15
vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
Normal file
15
vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package metadata
|
||||||
|
|
||||||
|
// ClientInfo wraps immutable data from the client.Client structure.
|
||||||
|
type ClientInfo struct {
|
||||||
|
ServiceName string
|
||||||
|
ServiceID string
|
||||||
|
APIVersion string
|
||||||
|
PartitionID string
|
||||||
|
Endpoint string
|
||||||
|
SigningName string
|
||||||
|
SigningRegion string
|
||||||
|
JSONVersion string
|
||||||
|
TargetPrefix string
|
||||||
|
ResolvedRegion string
|
||||||
|
}
|
28
vendor/github.com/aws/aws-sdk-go/aws/client/no_op_retryer.go
generated
vendored
Normal file
28
vendor/github.com/aws/aws-sdk-go/aws/client/no_op_retryer.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NoOpRetryer provides a retryer that performs no retries.
|
||||||
|
// It should be used when we do not want retries to be performed.
|
||||||
|
type NoOpRetryer struct{}
|
||||||
|
|
||||||
|
// MaxRetries returns the number of maximum returns the service will use to make
|
||||||
|
// an individual API; For NoOpRetryer the MaxRetries will always be zero.
|
||||||
|
func (d NoOpRetryer) MaxRetries() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldRetry will always return false for NoOpRetryer, as it should never retry.
|
||||||
|
func (d NoOpRetryer) ShouldRetry(_ *request.Request) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetryRules returns the delay duration before retrying this request again;
|
||||||
|
// since NoOpRetryer does not retry, RetryRules always returns 0.
|
||||||
|
func (d NoOpRetryer) RetryRules(_ *request.Request) time.Duration {
|
||||||
|
return 0
|
||||||
|
}
|
631
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
Normal file
631
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
Normal file
@ -0,0 +1,631 @@
|
|||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UseServiceDefaultRetries instructs the config to use the service's own
|
||||||
|
// default number of retries. This will be the default action if
|
||||||
|
// Config.MaxRetries is nil also.
|
||||||
|
const UseServiceDefaultRetries = -1
|
||||||
|
|
||||||
|
// RequestRetryer is an alias for a type that implements the request.Retryer
|
||||||
|
// interface.
|
||||||
|
type RequestRetryer interface{}
|
||||||
|
|
||||||
|
// A Config provides service configuration for service clients. By default,
|
||||||
|
// all clients will use the defaults.DefaultConfig structure.
|
||||||
|
//
|
||||||
|
// // Create Session with MaxRetries configuration to be shared by multiple
|
||||||
|
// // service clients.
|
||||||
|
// sess := session.Must(session.NewSession(&aws.Config{
|
||||||
|
// MaxRetries: aws.Int(3),
|
||||||
|
// }))
|
||||||
|
//
|
||||||
|
// // Create S3 service client with a specific Region.
|
||||||
|
// svc := s3.New(sess, &aws.Config{
|
||||||
|
// Region: aws.String("us-west-2"),
|
||||||
|
// })
|
||||||
|
type Config struct {
|
||||||
|
// Enables verbose error printing of all credential chain errors.
|
||||||
|
// Should be used when wanting to see all errors while attempting to
|
||||||
|
// retrieve credentials.
|
||||||
|
CredentialsChainVerboseErrors *bool
|
||||||
|
|
||||||
|
// The credentials object to use when signing requests. Defaults to a
|
||||||
|
// chain of credential providers to search for credentials in environment
|
||||||
|
// variables, shared credential file, and EC2 Instance Roles.
|
||||||
|
Credentials *credentials.Credentials
|
||||||
|
|
||||||
|
// An optional endpoint URL (hostname only or fully qualified URI)
|
||||||
|
// that overrides the default generated endpoint for a client. Set this
|
||||||
|
// to `nil` or the value to `""` to use the default generated endpoint.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
// to use based on region.
|
||||||
|
EndpointResolver endpoints.Resolver
|
||||||
|
|
||||||
|
// EnforceShouldRetryCheck is used in the AfterRetryHandler to always call
|
||||||
|
// ShouldRetry regardless of whether or not if request.Retryable is set.
|
||||||
|
// This will utilize ShouldRetry method of custom retryers. If EnforceShouldRetryCheck
|
||||||
|
// is not set, then ShouldRetry will only be called if request.Retryable is nil.
|
||||||
|
// Proper handling of the request.Retryable field is important when setting this field.
|
||||||
|
EnforceShouldRetryCheck *bool
|
||||||
|
|
||||||
|
// The region to send requests to. This parameter is required and must
|
||||||
|
// be configured globally or on a per-client basis unless otherwise
|
||||||
|
// 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 for AWS
|
||||||
|
// Regions and Endpoints.
|
||||||
|
Region *string
|
||||||
|
|
||||||
|
// Set this to `true` to disable SSL when sending requests. Defaults
|
||||||
|
// to `false`.
|
||||||
|
DisableSSL *bool
|
||||||
|
|
||||||
|
// The HTTP client to use when sending requests. Defaults to
|
||||||
|
// `http.DefaultClient`.
|
||||||
|
HTTPClient *http.Client
|
||||||
|
|
||||||
|
// An integer value representing the logging level. The default log level
|
||||||
|
// is zero (LogOff), which represents no logging. To enable logging set
|
||||||
|
// to a LogLevel Value.
|
||||||
|
LogLevel *LogLevelType
|
||||||
|
|
||||||
|
// The logger writer interface to write logging messages to. Defaults to
|
||||||
|
// standard out.
|
||||||
|
Logger Logger
|
||||||
|
|
||||||
|
// The maximum number of times that a request will be retried for failures.
|
||||||
|
// Defaults to -1, which defers the max retry setting to the service
|
||||||
|
// specific configuration.
|
||||||
|
MaxRetries *int
|
||||||
|
|
||||||
|
// Retryer guides how HTTP requests should be retried in case of
|
||||||
|
// recoverable failures.
|
||||||
|
//
|
||||||
|
// When nil or the value does not implement the request.Retryer interface,
|
||||||
|
// the client.DefaultRetryer will be used.
|
||||||
|
//
|
||||||
|
// When both Retryer and MaxRetries are non-nil, the former is used and
|
||||||
|
// the latter ignored.
|
||||||
|
//
|
||||||
|
// To set the Retryer field in a type-safe manner and with chaining, use
|
||||||
|
// the request.WithRetryer helper function:
|
||||||
|
//
|
||||||
|
// cfg := request.WithRetryer(aws.NewConfig(), myRetryer)
|
||||||
|
//
|
||||||
|
Retryer RequestRetryer
|
||||||
|
|
||||||
|
// Disables semantic parameter validation, which validates input for
|
||||||
|
// missing required fields and/or other semantic request input errors.
|
||||||
|
DisableParamValidation *bool
|
||||||
|
|
||||||
|
// Disables the computation of request and response checksums, e.g.,
|
||||||
|
// CRC32 checksums in Amazon DynamoDB.
|
||||||
|
DisableComputeChecksums *bool
|
||||||
|
|
||||||
|
// Set this to `true` to force the request to use path-style addressing,
|
||||||
|
// i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client
|
||||||
|
// 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
|
||||||
|
// for Amazon S3: Virtual Hosting of Buckets
|
||||||
|
S3ForcePathStyle *bool
|
||||||
|
|
||||||
|
// Set this to `true` to disable the SDK adding the `Expect: 100-Continue`
|
||||||
|
// header to PUT requests over 2MB of content. 100-Continue instructs the
|
||||||
|
// HTTP client not to send the body until the service responds with a
|
||||||
|
// `continue` status. This is useful to prevent sending the request body
|
||||||
|
// until after the request is authenticated, and validated.
|
||||||
|
//
|
||||||
|
// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html
|
||||||
|
//
|
||||||
|
// 100-Continue is only enabled for Go 1.6 and above. See `http.Transport`'s
|
||||||
|
// `ExpectContinueTimeout` for information on adjusting the continue wait
|
||||||
|
// timeout. https://golang.org/pkg/net/http/#Transport
|
||||||
|
//
|
||||||
|
// You should use this flag to disable 100-Continue if you experience issues
|
||||||
|
// with proxies or third party S3 compatible services.
|
||||||
|
S3Disable100Continue *bool
|
||||||
|
|
||||||
|
// Set this to `true` to enable S3 Accelerate feature. For all operations
|
||||||
|
// compatible with S3 Accelerate will use the accelerate endpoint for
|
||||||
|
// requests. Requests not compatible will fall back to normal S3 requests.
|
||||||
|
//
|
||||||
|
// The bucket must be enable for accelerate to be used with S3 client with
|
||||||
|
// accelerate enabled. If the bucket is not enabled for accelerate an error
|
||||||
|
// will be returned. The bucket name must be DNS compatible to also work
|
||||||
|
// 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 have the S3 service client to use the region specified
|
||||||
|
// in the ARN, when an ARN is provided as an argument to a bucket parameter.
|
||||||
|
S3UseARNRegion *bool
|
||||||
|
|
||||||
|
// Set this to `true` to enable the SDK to unmarshal API response header maps to
|
||||||
|
// normalized lower case map keys.
|
||||||
|
//
|
||||||
|
// For example S3's X-Amz-Meta prefixed header will be unmarshaled to lower case
|
||||||
|
// Metadata member's map keys. The value of the header in the map is unaffected.
|
||||||
|
//
|
||||||
|
// The AWS SDK for Go v2, uses lower case header maps by default. The v1
|
||||||
|
// SDK provides this opt-in for this option, for backwards compatibility.
|
||||||
|
LowerCaseHeaderMaps *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
|
||||||
|
// meaningful if you're not already using a custom HTTP client with the
|
||||||
|
// SDK. Enabled by default.
|
||||||
|
//
|
||||||
|
// Must be set and provided to the session.NewSession() in order to disable
|
||||||
|
// the EC2Metadata overriding the timeout for default credentials chain.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// sess := session.Must(session.NewSession(aws.NewConfig()
|
||||||
|
// .WithEC2MetadataDisableTimeoutOverride(true)))
|
||||||
|
//
|
||||||
|
// svc := s3.New(sess)
|
||||||
|
//
|
||||||
|
EC2MetadataDisableTimeoutOverride *bool
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Setting this for a service which does not support dual stack will fail
|
||||||
|
// to make requests. It is not recommended to set this value on the session
|
||||||
|
// as it will apply to all service clients created with the session. Even
|
||||||
|
// services which don't support dual stack endpoints.
|
||||||
|
//
|
||||||
|
// If the Endpoint config value is also provided the UseDualStack flag
|
||||||
|
// will be ignored.
|
||||||
|
//
|
||||||
|
// Only supported with.
|
||||||
|
//
|
||||||
|
// sess := session.Must(session.NewSession())
|
||||||
|
//
|
||||||
|
// svc := s3.New(sess, &aws.Config{
|
||||||
|
// UseDualStack: aws.Bool(true),
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// Deprecated: This option will continue to function for S3 and S3 Control for backwards compatibility.
|
||||||
|
// UseDualStackEndpoint should be used to enable usage of a service's dual-stack endpoint for all service clients
|
||||||
|
// moving forward. For S3 and S3 Control, when UseDualStackEndpoint is set to a non-zero value it takes higher
|
||||||
|
// precedence then this option.
|
||||||
|
UseDualStack *bool
|
||||||
|
|
||||||
|
// Sets the resolver to resolve a dual-stack endpoint for the service.
|
||||||
|
UseDualStackEndpoint endpoints.DualStackEndpointState
|
||||||
|
|
||||||
|
// UseFIPSEndpoint specifies the resolver must resolve a FIPS endpoint.
|
||||||
|
UseFIPSEndpoint endpoints.FIPSEndpointState
|
||||||
|
|
||||||
|
// SleepDelay is an override for the func the SDK will call when sleeping
|
||||||
|
// during the lifecycle of a request. Specifically this will be used for
|
||||||
|
// request delays. This value should only be used for testing. To adjust
|
||||||
|
// the delay of a request see the aws/client.DefaultRetryer and
|
||||||
|
// aws/request.Retryer.
|
||||||
|
//
|
||||||
|
// SleepDelay will prevent any Context from being used for canceling retry
|
||||||
|
// delay of an API operation. It is recommended to not use SleepDelay at all
|
||||||
|
// and specify a Retryer instead.
|
||||||
|
SleepDelay func(time.Duration)
|
||||||
|
|
||||||
|
// DisableRestProtocolURICleaning will not clean the URL path when making rest protocol requests.
|
||||||
|
// Will default to false. This would only be used for empty directory names in s3 requests.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// sess := session.Must(session.NewSession(&aws.Config{
|
||||||
|
// DisableRestProtocolURICleaning: aws.Bool(true),
|
||||||
|
// }))
|
||||||
|
//
|
||||||
|
// svc := s3.New(sess)
|
||||||
|
// out, err := svc.GetObject(&s3.GetObjectInput {
|
||||||
|
// Bucket: aws.String("bucketname"),
|
||||||
|
// 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.
|
||||||
|
// To use EndpointDiscovery, Endpoint should be unset or set to an empty string.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// STSRegionalEndpoint will enable regional or legacy endpoint resolving
|
||||||
|
STSRegionalEndpoint endpoints.STSRegionalEndpoint
|
||||||
|
|
||||||
|
// S3UsEast1RegionalEndpoint will enable regional or legacy endpoint resolving
|
||||||
|
S3UsEast1RegionalEndpoint endpoints.S3UsEast1RegionalEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConfig returns a new Config pointer that can be chained with builder
|
||||||
|
// methods to set multiple configuration values inline without using pointers.
|
||||||
|
//
|
||||||
|
// // Create Session with MaxRetries configuration to be shared by multiple
|
||||||
|
// // service clients.
|
||||||
|
// sess := session.Must(session.NewSession(aws.NewConfig().
|
||||||
|
// WithMaxRetries(3),
|
||||||
|
// ))
|
||||||
|
//
|
||||||
|
// // Create S3 service client with a specific Region.
|
||||||
|
// svc := s3.New(sess, aws.NewConfig().
|
||||||
|
// WithRegion("us-west-2"),
|
||||||
|
// )
|
||||||
|
func NewConfig() *Config {
|
||||||
|
return &Config{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCredentialsChainVerboseErrors sets a config verbose errors boolean and returning
|
||||||
|
// a Config pointer.
|
||||||
|
func (c *Config) WithCredentialsChainVerboseErrors(verboseErrs bool) *Config {
|
||||||
|
c.CredentialsChainVerboseErrors = &verboseErrs
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCredentials sets a config Credentials value returning a Config pointer
|
||||||
|
// for chaining.
|
||||||
|
func (c *Config) WithCredentials(creds *credentials.Credentials) *Config {
|
||||||
|
c.Credentials = creds
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEndpoint sets a config Endpoint value returning a Config pointer for
|
||||||
|
// chaining.
|
||||||
|
func (c *Config) WithEndpoint(endpoint string) *Config {
|
||||||
|
c.Endpoint = &endpoint
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEndpointResolver sets a config EndpointResolver value returning a
|
||||||
|
// Config pointer for chaining.
|
||||||
|
func (c *Config) WithEndpointResolver(resolver endpoints.Resolver) *Config {
|
||||||
|
c.EndpointResolver = resolver
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRegion sets a config Region value returning a Config pointer for
|
||||||
|
// chaining.
|
||||||
|
func (c *Config) WithRegion(region string) *Config {
|
||||||
|
c.Region = ®ion
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDisableSSL sets a config DisableSSL value returning a Config pointer
|
||||||
|
// for chaining.
|
||||||
|
func (c *Config) WithDisableSSL(disable bool) *Config {
|
||||||
|
c.DisableSSL = &disable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHTTPClient sets a config HTTPClient value returning a Config pointer
|
||||||
|
// for chaining.
|
||||||
|
func (c *Config) WithHTTPClient(client *http.Client) *Config {
|
||||||
|
c.HTTPClient = client
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxRetries sets a config MaxRetries value returning a Config pointer
|
||||||
|
// for chaining.
|
||||||
|
func (c *Config) WithMaxRetries(max int) *Config {
|
||||||
|
c.MaxRetries = &max
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDisableParamValidation sets a config DisableParamValidation value
|
||||||
|
// returning a Config pointer for chaining.
|
||||||
|
func (c *Config) WithDisableParamValidation(disable bool) *Config {
|
||||||
|
c.DisableParamValidation = &disable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDisableComputeChecksums sets a config DisableComputeChecksums value
|
||||||
|
// returning a Config pointer for chaining.
|
||||||
|
func (c *Config) WithDisableComputeChecksums(disable bool) *Config {
|
||||||
|
c.DisableComputeChecksums = &disable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLogLevel sets a config LogLevel value returning a Config pointer for
|
||||||
|
// chaining.
|
||||||
|
func (c *Config) WithLogLevel(level LogLevelType) *Config {
|
||||||
|
c.LogLevel = &level
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLogger sets a config Logger value returning a Config pointer for
|
||||||
|
// chaining.
|
||||||
|
func (c *Config) WithLogger(logger Logger) *Config {
|
||||||
|
c.Logger = logger
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithS3ForcePathStyle sets a config S3ForcePathStyle value returning a Config
|
||||||
|
// pointer for chaining.
|
||||||
|
func (c *Config) WithS3ForcePathStyle(force bool) *Config {
|
||||||
|
c.S3ForcePathStyle = &force
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithS3Disable100Continue sets a config S3Disable100Continue value returning
|
||||||
|
// a Config pointer for chaining.
|
||||||
|
func (c *Config) WithS3Disable100Continue(disable bool) *Config {
|
||||||
|
c.S3Disable100Continue = &disable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithS3UseAccelerate sets a config S3UseAccelerate value returning a Config
|
||||||
|
// pointer for chaining.
|
||||||
|
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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithS3UseARNRegion sets a config S3UseARNRegion value and
|
||||||
|
// returning a Config pointer for chaining
|
||||||
|
func (c *Config) WithS3UseARNRegion(enable bool) *Config {
|
||||||
|
c.S3UseARNRegion = &enable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithUseDualStack sets a config UseDualStack value returning a Config
|
||||||
|
// pointer for chaining.
|
||||||
|
func (c *Config) WithUseDualStack(enable bool) *Config {
|
||||||
|
c.UseDualStack = &enable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEC2MetadataDisableTimeoutOverride sets a config EC2MetadataDisableTimeoutOverride value
|
||||||
|
// returning a Config pointer for chaining.
|
||||||
|
func (c *Config) WithEC2MetadataDisableTimeoutOverride(enable bool) *Config {
|
||||||
|
c.EC2MetadataDisableTimeoutOverride = &enable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSleepDelay overrides the function used to sleep while waiting for the
|
||||||
|
// next retry. Defaults to time.Sleep.
|
||||||
|
func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config {
|
||||||
|
c.SleepDelay = fn
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSTSRegionalEndpoint will set whether or not to use regional endpoint flag
|
||||||
|
// when resolving the endpoint for a service
|
||||||
|
func (c *Config) WithSTSRegionalEndpoint(sre endpoints.STSRegionalEndpoint) *Config {
|
||||||
|
c.STSRegionalEndpoint = sre
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithS3UsEast1RegionalEndpoint will set whether or not to use regional endpoint flag
|
||||||
|
// when resolving the endpoint for a service
|
||||||
|
func (c *Config) WithS3UsEast1RegionalEndpoint(sre endpoints.S3UsEast1RegionalEndpoint) *Config {
|
||||||
|
c.S3UsEast1RegionalEndpoint = sre
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLowerCaseHeaderMaps sets a config LowerCaseHeaderMaps value
|
||||||
|
// returning a Config pointer for chaining.
|
||||||
|
func (c *Config) WithLowerCaseHeaderMaps(t bool) *Config {
|
||||||
|
c.LowerCaseHeaderMaps = &t
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDisableRestProtocolURICleaning sets a config DisableRestProtocolURICleaning value
|
||||||
|
// returning a Config pointer for chaining.
|
||||||
|
func (c *Config) WithDisableRestProtocolURICleaning(t bool) *Config {
|
||||||
|
c.DisableRestProtocolURICleaning = &t
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeIn merges the passed in configs into the existing config object.
|
||||||
|
func (c *Config) MergeIn(cfgs ...*Config) {
|
||||||
|
for _, other := range cfgs {
|
||||||
|
mergeInConfig(c, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeInConfig(dst *Config, other *Config) {
|
||||||
|
if other == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.CredentialsChainVerboseErrors != nil {
|
||||||
|
dst.CredentialsChainVerboseErrors = other.CredentialsChainVerboseErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Credentials != nil {
|
||||||
|
dst.Credentials = other.Credentials
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Endpoint != nil {
|
||||||
|
dst.Endpoint = other.Endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.EndpointResolver != nil {
|
||||||
|
dst.EndpointResolver = other.EndpointResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Region != nil {
|
||||||
|
dst.Region = other.Region
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.DisableSSL != nil {
|
||||||
|
dst.DisableSSL = other.DisableSSL
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.HTTPClient != nil {
|
||||||
|
dst.HTTPClient = other.HTTPClient
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.LogLevel != nil {
|
||||||
|
dst.LogLevel = other.LogLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Logger != nil {
|
||||||
|
dst.Logger = other.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.MaxRetries != nil {
|
||||||
|
dst.MaxRetries = other.MaxRetries
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Retryer != nil {
|
||||||
|
dst.Retryer = other.Retryer
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.DisableParamValidation != nil {
|
||||||
|
dst.DisableParamValidation = other.DisableParamValidation
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.DisableComputeChecksums != nil {
|
||||||
|
dst.DisableComputeChecksums = other.DisableComputeChecksums
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3ForcePathStyle != nil {
|
||||||
|
dst.S3ForcePathStyle = other.S3ForcePathStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3Disable100Continue != nil {
|
||||||
|
dst.S3Disable100Continue = other.S3Disable100Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3UseAccelerate != nil {
|
||||||
|
dst.S3UseAccelerate = other.S3UseAccelerate
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3DisableContentMD5Validation != nil {
|
||||||
|
dst.S3DisableContentMD5Validation = other.S3DisableContentMD5Validation
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3UseARNRegion != nil {
|
||||||
|
dst.S3UseARNRegion = other.S3UseARNRegion
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.UseDualStack != nil {
|
||||||
|
dst.UseDualStack = other.UseDualStack
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.UseDualStackEndpoint != endpoints.DualStackEndpointStateUnset {
|
||||||
|
dst.UseDualStackEndpoint = other.UseDualStackEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.EC2MetadataDisableTimeoutOverride != nil {
|
||||||
|
dst.EC2MetadataDisableTimeoutOverride = other.EC2MetadataDisableTimeoutOverride
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.SleepDelay != nil {
|
||||||
|
dst.SleepDelay = other.SleepDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.DisableRestProtocolURICleaning != nil {
|
||||||
|
dst.DisableRestProtocolURICleaning = other.DisableRestProtocolURICleaning
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.EnforceShouldRetryCheck != nil {
|
||||||
|
dst.EnforceShouldRetryCheck = other.EnforceShouldRetryCheck
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.EnableEndpointDiscovery != nil {
|
||||||
|
dst.EnableEndpointDiscovery = other.EnableEndpointDiscovery
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.DisableEndpointHostPrefix != nil {
|
||||||
|
dst.DisableEndpointHostPrefix = other.DisableEndpointHostPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.STSRegionalEndpoint != endpoints.UnsetSTSEndpoint {
|
||||||
|
dst.STSRegionalEndpoint = other.STSRegionalEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3UsEast1RegionalEndpoint != endpoints.UnsetS3UsEast1Endpoint {
|
||||||
|
dst.S3UsEast1RegionalEndpoint = other.S3UsEast1RegionalEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.LowerCaseHeaderMaps != nil {
|
||||||
|
dst.LowerCaseHeaderMaps = other.LowerCaseHeaderMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.UseDualStackEndpoint != endpoints.DualStackEndpointStateUnset {
|
||||||
|
dst.UseDualStackEndpoint = other.UseDualStackEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.UseFIPSEndpoint != endpoints.FIPSEndpointStateUnset {
|
||||||
|
dst.UseFIPSEndpoint = other.UseFIPSEndpoint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy will return a shallow copy of the Config object. If any additional
|
||||||
|
// configurations are provided they will be merged into the new config returned.
|
||||||
|
func (c *Config) Copy(cfgs ...*Config) *Config {
|
||||||
|
dst := &Config{}
|
||||||
|
dst.MergeIn(c)
|
||||||
|
|
||||||
|
for _, cfg := range cfgs {
|
||||||
|
dst.MergeIn(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
38
vendor/github.com/aws/aws-sdk-go/aws/context_1_5.go
generated
vendored
Normal file
38
vendor/github.com/aws/aws-sdk-go/aws/context_1_5.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//go:build !go1.9
|
||||||
|
// +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{}
|
||||||
|
}
|
12
vendor/github.com/aws/aws-sdk-go/aws/context_1_9.go
generated
vendored
Normal file
12
vendor/github.com/aws/aws-sdk-go/aws/context_1_9.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//go:build go1.9
|
||||||
|
// +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
|
23
vendor/github.com/aws/aws-sdk-go/aws/context_background_1_5.go
generated
vendored
Normal file
23
vendor/github.com/aws/aws-sdk-go/aws/context_background_1_5.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//go:build !go1.7
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/internal/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.BackgroundCtx
|
||||||
|
}
|
21
vendor/github.com/aws/aws-sdk-go/aws/context_background_1_7.go
generated
vendored
Normal file
21
vendor/github.com/aws/aws-sdk-go/aws/context_background_1_7.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//go:build go1.7
|
||||||
|
// +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
|
||||||
|
}
|
918
vendor/github.com/aws/aws-sdk-go/aws/convert_types.go
generated
vendored
Normal file
918
vendor/github.com/aws/aws-sdk-go/aws/convert_types.go
generated
vendored
Normal file
@ -0,0 +1,918 @@
|
|||||||
|
package aws
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// String returns a pointer to the string value passed in.
|
||||||
|
func String(v string) *string {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringValue returns the value of the string pointer passed in or
|
||||||
|
// "" if the pointer is nil.
|
||||||
|
func StringValue(v *string) string {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice converts a slice of string values into a slice of
|
||||||
|
// string pointers
|
||||||
|
func StringSlice(src []string) []*string {
|
||||||
|
dst := make([]*string, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringValueSlice converts a slice of string pointers into a slice of
|
||||||
|
// string values
|
||||||
|
func StringValueSlice(src []*string) []string {
|
||||||
|
dst := make([]string, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringMap converts a string map of string values into a string
|
||||||
|
// map of string pointers
|
||||||
|
func StringMap(src map[string]string) map[string]*string {
|
||||||
|
dst := make(map[string]*string)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringValueMap converts a string map of string pointers into a string
|
||||||
|
// map of string values
|
||||||
|
func StringValueMap(src map[string]*string) map[string]string {
|
||||||
|
dst := make(map[string]string)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool returns a pointer to the bool value passed in.
|
||||||
|
func Bool(v bool) *bool {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolValue returns the value of the bool pointer passed in or
|
||||||
|
// false if the pointer is nil.
|
||||||
|
func BoolValue(v *bool) bool {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSlice converts a slice of bool values into a slice of
|
||||||
|
// bool pointers
|
||||||
|
func BoolSlice(src []bool) []*bool {
|
||||||
|
dst := make([]*bool, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolValueSlice converts a slice of bool pointers into a slice of
|
||||||
|
// bool values
|
||||||
|
func BoolValueSlice(src []*bool) []bool {
|
||||||
|
dst := make([]bool, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolMap converts a string map of bool values into a string
|
||||||
|
// map of bool pointers
|
||||||
|
func BoolMap(src map[string]bool) map[string]*bool {
|
||||||
|
dst := make(map[string]*bool)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolValueMap converts a string map of bool pointers into a string
|
||||||
|
// map of bool values
|
||||||
|
func BoolValueMap(src map[string]*bool) map[string]bool {
|
||||||
|
dst := make(map[string]bool)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int returns a pointer to the int value passed in.
|
||||||
|
func Int(v int) *int {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntValue returns the value of the int pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func IntValue(v *int) int {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntSlice converts a slice of int values into a slice of
|
||||||
|
// int pointers
|
||||||
|
func IntSlice(src []int) []*int {
|
||||||
|
dst := make([]*int, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntValueSlice converts a slice of int pointers into a slice of
|
||||||
|
// int values
|
||||||
|
func IntValueSlice(src []*int) []int {
|
||||||
|
dst := make([]int, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntMap converts a string map of int values into a string
|
||||||
|
// map of int pointers
|
||||||
|
func IntMap(src map[string]int) map[string]*int {
|
||||||
|
dst := make(map[string]*int)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntValueMap converts a string map of int pointers into a string
|
||||||
|
// map of int values
|
||||||
|
func IntValueMap(src map[string]*int) map[string]int {
|
||||||
|
dst := make(map[string]int)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint returns a pointer to the uint value passed in.
|
||||||
|
func Uint(v uint) *uint {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintValue returns the value of the uint pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func UintValue(v *uint) uint {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintSlice converts a slice of uint values uinto a slice of
|
||||||
|
// uint pointers
|
||||||
|
func UintSlice(src []uint) []*uint {
|
||||||
|
dst := make([]*uint, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintValueSlice converts a slice of uint pointers uinto a slice of
|
||||||
|
// uint values
|
||||||
|
func UintValueSlice(src []*uint) []uint {
|
||||||
|
dst := make([]uint, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintMap converts a string map of uint values uinto a string
|
||||||
|
// map of uint pointers
|
||||||
|
func UintMap(src map[string]uint) map[string]*uint {
|
||||||
|
dst := make(map[string]*uint)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintValueMap converts a string map of uint pointers uinto a string
|
||||||
|
// map of uint values
|
||||||
|
func UintValueMap(src map[string]*uint) map[string]uint {
|
||||||
|
dst := make(map[string]uint)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int8 returns a pointer to the int8 value passed in.
|
||||||
|
func Int8(v int8) *int8 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int8Value returns the value of the int8 pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func Int8Value(v *int8) int8 {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int8Slice converts a slice of int8 values into a slice of
|
||||||
|
// int8 pointers
|
||||||
|
func Int8Slice(src []int8) []*int8 {
|
||||||
|
dst := make([]*int8, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int8ValueSlice converts a slice of int8 pointers into a slice of
|
||||||
|
// int8 values
|
||||||
|
func Int8ValueSlice(src []*int8) []int8 {
|
||||||
|
dst := make([]int8, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int8Map converts a string map of int8 values into a string
|
||||||
|
// map of int8 pointers
|
||||||
|
func Int8Map(src map[string]int8) map[string]*int8 {
|
||||||
|
dst := make(map[string]*int8)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int8ValueMap converts a string map of int8 pointers into a string
|
||||||
|
// map of int8 values
|
||||||
|
func Int8ValueMap(src map[string]*int8) map[string]int8 {
|
||||||
|
dst := make(map[string]int8)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16 returns a pointer to the int16 value passed in.
|
||||||
|
func Int16(v int16) *int16 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16Value returns the value of the int16 pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func Int16Value(v *int16) int16 {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16Slice converts a slice of int16 values into a slice of
|
||||||
|
// int16 pointers
|
||||||
|
func Int16Slice(src []int16) []*int16 {
|
||||||
|
dst := make([]*int16, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16ValueSlice converts a slice of int16 pointers into a slice of
|
||||||
|
// int16 values
|
||||||
|
func Int16ValueSlice(src []*int16) []int16 {
|
||||||
|
dst := make([]int16, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16Map converts a string map of int16 values into a string
|
||||||
|
// map of int16 pointers
|
||||||
|
func Int16Map(src map[string]int16) map[string]*int16 {
|
||||||
|
dst := make(map[string]*int16)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16ValueMap converts a string map of int16 pointers into a string
|
||||||
|
// map of int16 values
|
||||||
|
func Int16ValueMap(src map[string]*int16) map[string]int16 {
|
||||||
|
dst := make(map[string]int16)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32 returns a pointer to the int32 value passed in.
|
||||||
|
func Int32(v int32) *int32 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32Value returns the value of the int32 pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func Int32Value(v *int32) int32 {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32Slice converts a slice of int32 values into a slice of
|
||||||
|
// int32 pointers
|
||||||
|
func Int32Slice(src []int32) []*int32 {
|
||||||
|
dst := make([]*int32, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32ValueSlice converts a slice of int32 pointers into a slice of
|
||||||
|
// int32 values
|
||||||
|
func Int32ValueSlice(src []*int32) []int32 {
|
||||||
|
dst := make([]int32, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32Map converts a string map of int32 values into a string
|
||||||
|
// map of int32 pointers
|
||||||
|
func Int32Map(src map[string]int32) map[string]*int32 {
|
||||||
|
dst := make(map[string]*int32)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32ValueMap converts a string map of int32 pointers into a string
|
||||||
|
// map of int32 values
|
||||||
|
func Int32ValueMap(src map[string]*int32) map[string]int32 {
|
||||||
|
dst := make(map[string]int32)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 returns a pointer to the int64 value passed in.
|
||||||
|
func Int64(v int64) *int64 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Value returns the value of the int64 pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func Int64Value(v *int64) int64 {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Slice converts a slice of int64 values into a slice of
|
||||||
|
// int64 pointers
|
||||||
|
func Int64Slice(src []int64) []*int64 {
|
||||||
|
dst := make([]*int64, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64ValueSlice converts a slice of int64 pointers into a slice of
|
||||||
|
// int64 values
|
||||||
|
func Int64ValueSlice(src []*int64) []int64 {
|
||||||
|
dst := make([]int64, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Map converts a string map of int64 values into a string
|
||||||
|
// map of int64 pointers
|
||||||
|
func Int64Map(src map[string]int64) map[string]*int64 {
|
||||||
|
dst := make(map[string]*int64)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64ValueMap converts a string map of int64 pointers into a string
|
||||||
|
// map of int64 values
|
||||||
|
func Int64ValueMap(src map[string]*int64) map[string]int64 {
|
||||||
|
dst := make(map[string]int64)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8 returns a pointer to the uint8 value passed in.
|
||||||
|
func Uint8(v uint8) *uint8 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8Value returns the value of the uint8 pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func Uint8Value(v *uint8) uint8 {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8Slice converts a slice of uint8 values into a slice of
|
||||||
|
// uint8 pointers
|
||||||
|
func Uint8Slice(src []uint8) []*uint8 {
|
||||||
|
dst := make([]*uint8, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8ValueSlice converts a slice of uint8 pointers into a slice of
|
||||||
|
// uint8 values
|
||||||
|
func Uint8ValueSlice(src []*uint8) []uint8 {
|
||||||
|
dst := make([]uint8, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8Map converts a string map of uint8 values into a string
|
||||||
|
// map of uint8 pointers
|
||||||
|
func Uint8Map(src map[string]uint8) map[string]*uint8 {
|
||||||
|
dst := make(map[string]*uint8)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8ValueMap converts a string map of uint8 pointers into a string
|
||||||
|
// map of uint8 values
|
||||||
|
func Uint8ValueMap(src map[string]*uint8) map[string]uint8 {
|
||||||
|
dst := make(map[string]uint8)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint16 returns a pointer to the uint16 value passed in.
|
||||||
|
func Uint16(v uint16) *uint16 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint16Value returns the value of the uint16 pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func Uint16Value(v *uint16) uint16 {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint16Slice converts a slice of uint16 values into a slice of
|
||||||
|
// uint16 pointers
|
||||||
|
func Uint16Slice(src []uint16) []*uint16 {
|
||||||
|
dst := make([]*uint16, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint16ValueSlice converts a slice of uint16 pointers into a slice of
|
||||||
|
// uint16 values
|
||||||
|
func Uint16ValueSlice(src []*uint16) []uint16 {
|
||||||
|
dst := make([]uint16, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint16Map converts a string map of uint16 values into a string
|
||||||
|
// map of uint16 pointers
|
||||||
|
func Uint16Map(src map[string]uint16) map[string]*uint16 {
|
||||||
|
dst := make(map[string]*uint16)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint16ValueMap converts a string map of uint16 pointers into a string
|
||||||
|
// map of uint16 values
|
||||||
|
func Uint16ValueMap(src map[string]*uint16) map[string]uint16 {
|
||||||
|
dst := make(map[string]uint16)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint32 returns a pointer to the uint32 value passed in.
|
||||||
|
func Uint32(v uint32) *uint32 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint32Value returns the value of the uint32 pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func Uint32Value(v *uint32) uint32 {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint32Slice converts a slice of uint32 values into a slice of
|
||||||
|
// uint32 pointers
|
||||||
|
func Uint32Slice(src []uint32) []*uint32 {
|
||||||
|
dst := make([]*uint32, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint32ValueSlice converts a slice of uint32 pointers into a slice of
|
||||||
|
// uint32 values
|
||||||
|
func Uint32ValueSlice(src []*uint32) []uint32 {
|
||||||
|
dst := make([]uint32, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint32Map converts a string map of uint32 values into a string
|
||||||
|
// map of uint32 pointers
|
||||||
|
func Uint32Map(src map[string]uint32) map[string]*uint32 {
|
||||||
|
dst := make(map[string]*uint32)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint32ValueMap converts a string map of uint32 pointers into a string
|
||||||
|
// map of uint32 values
|
||||||
|
func Uint32ValueMap(src map[string]*uint32) map[string]uint32 {
|
||||||
|
dst := make(map[string]uint32)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64 returns a pointer to the uint64 value passed in.
|
||||||
|
func Uint64(v uint64) *uint64 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64Value returns the value of the uint64 pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func Uint64Value(v *uint64) uint64 {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64Slice converts a slice of uint64 values into a slice of
|
||||||
|
// uint64 pointers
|
||||||
|
func Uint64Slice(src []uint64) []*uint64 {
|
||||||
|
dst := make([]*uint64, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64ValueSlice converts a slice of uint64 pointers into a slice of
|
||||||
|
// uint64 values
|
||||||
|
func Uint64ValueSlice(src []*uint64) []uint64 {
|
||||||
|
dst := make([]uint64, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64Map converts a string map of uint64 values into a string
|
||||||
|
// map of uint64 pointers
|
||||||
|
func Uint64Map(src map[string]uint64) map[string]*uint64 {
|
||||||
|
dst := make(map[string]*uint64)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64ValueMap converts a string map of uint64 pointers into a string
|
||||||
|
// map of uint64 values
|
||||||
|
func Uint64ValueMap(src map[string]*uint64) map[string]uint64 {
|
||||||
|
dst := make(map[string]uint64)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32 returns a pointer to the float32 value passed in.
|
||||||
|
func Float32(v float32) *float32 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32Value returns the value of the float32 pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func Float32Value(v *float32) float32 {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32Slice converts a slice of float32 values into a slice of
|
||||||
|
// float32 pointers
|
||||||
|
func Float32Slice(src []float32) []*float32 {
|
||||||
|
dst := make([]*float32, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32ValueSlice converts a slice of float32 pointers into a slice of
|
||||||
|
// float32 values
|
||||||
|
func Float32ValueSlice(src []*float32) []float32 {
|
||||||
|
dst := make([]float32, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32Map converts a string map of float32 values into a string
|
||||||
|
// map of float32 pointers
|
||||||
|
func Float32Map(src map[string]float32) map[string]*float32 {
|
||||||
|
dst := make(map[string]*float32)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32ValueMap converts a string map of float32 pointers into a string
|
||||||
|
// map of float32 values
|
||||||
|
func Float32ValueMap(src map[string]*float32) map[string]float32 {
|
||||||
|
dst := make(map[string]float32)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 returns a pointer to the float64 value passed in.
|
||||||
|
func Float64(v float64) *float64 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Value returns the value of the float64 pointer passed in or
|
||||||
|
// 0 if the pointer is nil.
|
||||||
|
func Float64Value(v *float64) float64 {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Slice converts a slice of float64 values into a slice of
|
||||||
|
// float64 pointers
|
||||||
|
func Float64Slice(src []float64) []*float64 {
|
||||||
|
dst := make([]*float64, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64ValueSlice converts a slice of float64 pointers into a slice of
|
||||||
|
// float64 values
|
||||||
|
func Float64ValueSlice(src []*float64) []float64 {
|
||||||
|
dst := make([]float64, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Map converts a string map of float64 values into a string
|
||||||
|
// map of float64 pointers
|
||||||
|
func Float64Map(src map[string]float64) map[string]*float64 {
|
||||||
|
dst := make(map[string]*float64)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64ValueMap converts a string map of float64 pointers into a string
|
||||||
|
// map of float64 values
|
||||||
|
func Float64ValueMap(src map[string]*float64) map[string]float64 {
|
||||||
|
dst := make(map[string]float64)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time returns a pointer to the time.Time value passed in.
|
||||||
|
func Time(v time.Time) *time.Time {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeValue returns the value of the time.Time pointer passed in or
|
||||||
|
// time.Time{} if the pointer is nil.
|
||||||
|
func TimeValue(v *time.Time) time.Time {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecondsTimeValue converts an int64 pointer to a time.Time value
|
||||||
|
// representing seconds since Epoch or time.Time{} if the pointer is nil.
|
||||||
|
func SecondsTimeValue(v *int64) time.Time {
|
||||||
|
if v != nil {
|
||||||
|
return time.Unix((*v / 1000), 0)
|
||||||
|
}
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MillisecondsTimeValue converts an int64 pointer to a time.Time value
|
||||||
|
// representing milliseconds sinch Epoch or time.Time{} if the pointer is nil.
|
||||||
|
func MillisecondsTimeValue(v *int64) time.Time {
|
||||||
|
if v != nil {
|
||||||
|
return time.Unix(0, (*v * 1000000))
|
||||||
|
}
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeUnixMilli returns a Unix timestamp in milliseconds from "January 1, 1970 UTC".
|
||||||
|
// The result is undefined if the Unix time cannot be represented by an int64.
|
||||||
|
// Which includes calling TimeUnixMilli on a zero Time is undefined.
|
||||||
|
//
|
||||||
|
// This utility is useful for service API's such as CloudWatch Logs which require
|
||||||
|
// their unix time values to be in milliseconds.
|
||||||
|
//
|
||||||
|
// See Go stdlib https://golang.org/pkg/time/#Time.UnixNano for more information.
|
||||||
|
func TimeUnixMilli(t time.Time) int64 {
|
||||||
|
return t.UnixNano() / int64(time.Millisecond/time.Nanosecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeSlice converts a slice of time.Time values into a slice of
|
||||||
|
// time.Time pointers
|
||||||
|
func TimeSlice(src []time.Time) []*time.Time {
|
||||||
|
dst := make([]*time.Time, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
dst[i] = &(src[i])
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeValueSlice converts a slice of time.Time pointers into a slice of
|
||||||
|
// time.Time values
|
||||||
|
func TimeValueSlice(src []*time.Time) []time.Time {
|
||||||
|
dst := make([]time.Time, len(src))
|
||||||
|
for i := 0; i < len(src); i++ {
|
||||||
|
if src[i] != nil {
|
||||||
|
dst[i] = *(src[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeMap converts a string map of time.Time values into a string
|
||||||
|
// map of time.Time pointers
|
||||||
|
func TimeMap(src map[string]time.Time) map[string]*time.Time {
|
||||||
|
dst := make(map[string]*time.Time)
|
||||||
|
for k, val := range src {
|
||||||
|
v := val
|
||||||
|
dst[k] = &v
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeValueMap converts a string map of time.Time pointers into a string
|
||||||
|
// map of time.Time values
|
||||||
|
func TimeValueMap(src map[string]*time.Time) map[string]time.Time {
|
||||||
|
dst := make(map[string]time.Time)
|
||||||
|
for k, val := range src {
|
||||||
|
if val != nil {
|
||||||
|
dst[k] = *val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
232
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
generated
vendored
Normal file
232
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
generated
vendored
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
package corehandlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface for matching types which also have a Len method.
|
||||||
|
type lener interface {
|
||||||
|
Len() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildContentLengthHandler builds the content length of a request based on the body,
|
||||||
|
// or will use the HTTPRequest.Header's "Content-Length" if defined. If unable
|
||||||
|
// to determine request body length and no "Content-Length" was specified it will panic.
|
||||||
|
//
|
||||||
|
// The Content-Length will only be added to the request if the length of the body
|
||||||
|
// is greater than 0. If the body is empty or the current `Content-Length`
|
||||||
|
// header is <= 0, the header will also be stripped.
|
||||||
|
var BuildContentLengthHandler = request.NamedHandler{Name: "core.BuildContentLengthHandler", Fn: func(r *request.Request) {
|
||||||
|
var length int64
|
||||||
|
|
||||||
|
if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" {
|
||||||
|
length, _ = strconv.ParseInt(slength, 10, 64)
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if length > 0 {
|
||||||
|
r.HTTPRequest.ContentLength = length
|
||||||
|
r.HTTPRequest.Header.Set("Content-Length", fmt.Sprintf("%d", length))
|
||||||
|
} else {
|
||||||
|
r.HTTPRequest.ContentLength = 0
|
||||||
|
r.HTTPRequest.Header.Del("Content-Length")
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
var reStatusCode = regexp.MustCompile(`^(\d{3})`)
|
||||||
|
|
||||||
|
// ValidateReqSigHandler is a request handler to ensure that the request's
|
||||||
|
// signature doesn't expire before it is sent. This can happen when a request
|
||||||
|
// is built and signed significantly before it is sent. Or significant delays
|
||||||
|
// occur when retrying requests that would cause the signature to expire.
|
||||||
|
var ValidateReqSigHandler = request.NamedHandler{
|
||||||
|
Name: "core.ValidateReqSigHandler",
|
||||||
|
Fn: func(r *request.Request) {
|
||||||
|
// Unsigned requests are not signed
|
||||||
|
if r.Config.Credentials == credentials.AnonymousCredentials {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
signedTime := r.Time
|
||||||
|
if !r.LastSignedAt.IsZero() {
|
||||||
|
signedTime = r.LastSignedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5 minutes to allow for some clock skew/delays in transmission.
|
||||||
|
// Would be improved with aws/aws-sdk-go#423
|
||||||
|
if signedTime.Add(5 * time.Minute).After(time.Now()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("request expired, resigning")
|
||||||
|
r.Sign()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendHandler is a request handler to send service request using HTTP client.
|
||||||
|
var SendHandler = request.NamedHandler{
|
||||||
|
Name: "core.SendHandler",
|
||||||
|
Fn: func(r *request.Request) {
|
||||||
|
sender := sendFollowRedirects
|
||||||
|
if r.DisableFollowRedirects {
|
||||||
|
sender = sendWithoutFollowRedirects
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.NoBody == r.HTTPRequest.Body {
|
||||||
|
// Strip off the request body if the NoBody reader was used as a
|
||||||
|
// place holder for a request body. This prevents the SDK from
|
||||||
|
// making requests with a request body when it would be invalid
|
||||||
|
// to do so.
|
||||||
|
//
|
||||||
|
// Use a shallow copy of the http.Request to ensure the race condition
|
||||||
|
// of transport on Body will not trigger
|
||||||
|
reqOrig, reqCopy := r.HTTPRequest, *r.HTTPRequest
|
||||||
|
reqCopy.Body = nil
|
||||||
|
r.HTTPRequest = &reqCopy
|
||||||
|
defer func() {
|
||||||
|
r.HTTPRequest = reqOrig
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
r.HTTPResponse, err = sender(r)
|
||||||
|
if err != nil {
|
||||||
|
handleSendError(r, err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendFollowRedirects(r *request.Request) (*http.Response, error) {
|
||||||
|
return r.Config.HTTPClient.Do(r.HTTPRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendWithoutFollowRedirects(r *request.Request) (*http.Response, error) {
|
||||||
|
transport := r.Config.HTTPClient.Transport
|
||||||
|
if transport == nil {
|
||||||
|
transport = http.DefaultTransport
|
||||||
|
}
|
||||||
|
|
||||||
|
return transport.RoundTrip(r.HTTPRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleSendError(r *request.Request, err error) {
|
||||||
|
// Prevent leaking if an HTTPResponse was returned. Clean up
|
||||||
|
// the body.
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
r.HTTPResponse.Body.Close()
|
||||||
|
}
|
||||||
|
// Capture the case where url.Error is returned for error processing
|
||||||
|
// response. e.g. 301 without location header comes back as string
|
||||||
|
// error and r.HTTPResponse is nil. Other URL redirect errors will
|
||||||
|
// comeback in a similar method.
|
||||||
|
if e, ok := err.(*url.Error); ok && e.Err != nil {
|
||||||
|
if s := reStatusCode.FindStringSubmatch(e.Err.Error()); s != nil {
|
||||||
|
code, _ := strconv.ParseInt(s[1], 10, 64)
|
||||||
|
r.HTTPResponse = &http.Response{
|
||||||
|
StatusCode: int(code),
|
||||||
|
Status: http.StatusText(int(code)),
|
||||||
|
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.HTTPResponse == nil {
|
||||||
|
// Add a dummy request response object to ensure the HTTPResponse
|
||||||
|
// value is consistent.
|
||||||
|
r.HTTPResponse = &http.Response{
|
||||||
|
StatusCode: int(0),
|
||||||
|
Status: http.StatusText(int(0)),
|
||||||
|
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Catch all request errors, and let the default retrier determine
|
||||||
|
// if the error is retryable.
|
||||||
|
r.Error = awserr.New(request.ErrCodeRequestError, "send request failed", err)
|
||||||
|
|
||||||
|
// Override the error with a context canceled error, if that was canceled.
|
||||||
|
ctx := r.Context()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
r.Error = awserr.New(request.CanceledErrorCode,
|
||||||
|
"request context canceled", ctx.Err())
|
||||||
|
r.Retryable = aws.Bool(false)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateResponseHandler is a request handler to validate service response.
|
||||||
|
var ValidateResponseHandler = request.NamedHandler{Name: "core.ValidateResponseHandler", Fn: func(r *request.Request) {
|
||||||
|
if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 {
|
||||||
|
// this may be replaced by an UnmarshalError handler
|
||||||
|
r.Error = awserr.New("UnknownError", "unknown error", r.Error)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
// AfterRetryHandler performs final checks to determine if the request should
|
||||||
|
// be retried and how long to delay.
|
||||||
|
var AfterRetryHandler = request.NamedHandler{
|
||||||
|
Name: "core.AfterRetryHandler",
|
||||||
|
Fn: func(r *request.Request) {
|
||||||
|
// If one of the other handlers already set the retry state
|
||||||
|
// we don't want to override it based on the service's state
|
||||||
|
if r.Retryable == nil || aws.BoolValue(r.Config.EnforceShouldRetryCheck) {
|
||||||
|
r.Retryable = aws.Bool(r.ShouldRetry(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.WillRetry() {
|
||||||
|
r.RetryDelay = r.RetryRules(r)
|
||||||
|
|
||||||
|
if sleepFn := r.Config.SleepDelay; sleepFn != nil {
|
||||||
|
// Support SleepDelay for backwards compatibility and testing
|
||||||
|
sleepFn(r.RetryDelay)
|
||||||
|
} else if err := aws.SleepWithContext(r.Context(), r.RetryDelay); err != nil {
|
||||||
|
r.Error = awserr.New(request.CanceledErrorCode,
|
||||||
|
"request context canceled", err)
|
||||||
|
r.Retryable = aws.Bool(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// when the expired token exception occurs the credentials
|
||||||
|
// need to be expired locally so that the next request to
|
||||||
|
// get credentials will trigger a credentials refresh.
|
||||||
|
if r.IsErrorExpired() {
|
||||||
|
r.Config.Credentials.Expire()
|
||||||
|
}
|
||||||
|
|
||||||
|
r.RetryCount++
|
||||||
|
r.Error = nil
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
// ValidateEndpointHandler is a request handler to validate a request had the
|
||||||
|
// appropriate Region and Endpoint set. Will set r.Error if the endpoint or
|
||||||
|
// region is not valid.
|
||||||
|
var ValidateEndpointHandler = request.NamedHandler{Name: "core.ValidateEndpointHandler", Fn: func(r *request.Request) {
|
||||||
|
if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" {
|
||||||
|
r.Error = aws.ErrMissingRegion
|
||||||
|
} else if r.ClientInfo.Endpoint == "" {
|
||||||
|
// Was any endpoint provided by the user, or one was derived by the
|
||||||
|
// SDK's endpoint resolver?
|
||||||
|
r.Error = aws.ErrMissingEndpoint
|
||||||
|
}
|
||||||
|
}}
|
17
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go
generated
vendored
Normal file
17
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package corehandlers
|
||||||
|
|
||||||
|
import "github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
|
||||||
|
// ValidateParametersHandler is a request handler to validate the input parameters.
|
||||||
|
// Validating parameters only has meaning if done prior to the request being sent.
|
||||||
|
var ValidateParametersHandler = request.NamedHandler{Name: "core.ValidateParametersHandler", Fn: func(r *request.Request) {
|
||||||
|
if !r.ParamsFilled() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := r.Params.(request.Validator); ok {
|
||||||
|
if err := v.Validate(); err != nil {
|
||||||
|
r.Error = 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)
|
||||||
|
},
|
||||||
|
}
|
100
vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go
generated
vendored
Normal file
100
vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrNoValidProvidersFoundInChain Is returned when there are no valid
|
||||||
|
// providers in the ChainProvider.
|
||||||
|
//
|
||||||
|
// This has been deprecated. For verbose error messaging set
|
||||||
|
// aws.Config.CredentialsChainVerboseErrors to true.
|
||||||
|
ErrNoValidProvidersFoundInChain = awserr.New("NoCredentialProviders",
|
||||||
|
`no valid providers in chain. Deprecated.
|
||||||
|
For verbose messaging see aws.Config.CredentialsChainVerboseErrors`,
|
||||||
|
nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
// A ChainProvider will search for a provider which returns credentials
|
||||||
|
// and cache that provider until Retrieve is called again.
|
||||||
|
//
|
||||||
|
// The ChainProvider provides a way of chaining multiple providers together
|
||||||
|
// which will pick the first available using priority order of the Providers
|
||||||
|
// in the list.
|
||||||
|
//
|
||||||
|
// If none of the Providers retrieve valid credentials Value, ChainProvider's
|
||||||
|
// Retrieve() will return the error ErrNoValidProvidersFoundInChain.
|
||||||
|
//
|
||||||
|
// If a Provider is found which returns valid credentials Value ChainProvider
|
||||||
|
// will cache that Provider for all calls to IsExpired(), until Retrieve is
|
||||||
|
// called again.
|
||||||
|
//
|
||||||
|
// Example of ChainProvider to be used with an EnvProvider and EC2RoleProvider.
|
||||||
|
// In this example EnvProvider will first check if any credentials are available
|
||||||
|
// via the environment variables. If there are none ChainProvider will check
|
||||||
|
// the next Provider in the list, EC2RoleProvider in this case. If EC2RoleProvider
|
||||||
|
// does not return any credentials ChainProvider will return the error
|
||||||
|
// ErrNoValidProvidersFoundInChain
|
||||||
|
//
|
||||||
|
// creds := credentials.NewChainCredentials(
|
||||||
|
// []credentials.Provider{
|
||||||
|
// &credentials.EnvProvider{},
|
||||||
|
// &ec2rolecreds.EC2RoleProvider{
|
||||||
|
// Client: ec2metadata.New(sess),
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// // Usage of ChainCredentials with aws.Config
|
||||||
|
// svc := ec2.New(session.Must(session.NewSession(&aws.Config{
|
||||||
|
// Credentials: creds,
|
||||||
|
// })))
|
||||||
|
//
|
||||||
|
type ChainProvider struct {
|
||||||
|
Providers []Provider
|
||||||
|
curr Provider
|
||||||
|
VerboseErrors bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewChainCredentials returns a pointer to a new Credentials object
|
||||||
|
// wrapping a chain of providers.
|
||||||
|
func NewChainCredentials(providers []Provider) *Credentials {
|
||||||
|
return NewCredentials(&ChainProvider{
|
||||||
|
Providers: append([]Provider{}, providers...),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve returns the credentials value or error if no provider returned
|
||||||
|
// without error.
|
||||||
|
//
|
||||||
|
// If a provider is found it will be cached and any calls to IsExpired()
|
||||||
|
// will return the expired state of the cached provider.
|
||||||
|
func (c *ChainProvider) Retrieve() (Value, error) {
|
||||||
|
var errs []error
|
||||||
|
for _, p := range c.Providers {
|
||||||
|
creds, err := p.Retrieve()
|
||||||
|
if err == nil {
|
||||||
|
c.curr = p
|
||||||
|
return creds, nil
|
||||||
|
}
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
c.curr = nil
|
||||||
|
|
||||||
|
var err error
|
||||||
|
err = ErrNoValidProvidersFoundInChain
|
||||||
|
if c.VerboseErrors {
|
||||||
|
err = awserr.NewBatchError("NoCredentialProviders", "no valid providers in chain", errs)
|
||||||
|
}
|
||||||
|
return Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired will returned the expired state of the currently cached provider
|
||||||
|
// if there is one. If there is no current provider, true will be returned.
|
||||||
|
func (c *ChainProvider) IsExpired() bool {
|
||||||
|
if c.curr != nil {
|
||||||
|
return c.curr.IsExpired()
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
23
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_background_go1.5.go
generated
vendored
Normal file
23
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_background_go1.5.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//go:build !go1.7
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/internal/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.BackgroundCtx
|
||||||
|
}
|
21
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_background_go1.7.go
generated
vendored
Normal file
21
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_background_go1.7.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//go:build go1.7
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
40
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_go1.5.go
generated
vendored
Normal file
40
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_go1.5.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//go:build !go1.9
|
||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
// This type, aws.Context, and context.Context are equivalent.
|
||||||
|
//
|
||||||
|
// 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{}
|
||||||
|
}
|
14
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_go1.9.go
generated
vendored
Normal file
14
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_go1.9.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//go:build go1.9
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
// This type, aws.Context, and context.Context are equivalent.
|
||||||
|
//
|
||||||
|
// See https://golang.org/pkg/context on how to use contexts.
|
||||||
|
type Context = context.Context
|
383
vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials.go
generated
vendored
Normal file
383
vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials.go
generated
vendored
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
// Package credentials provides credential retrieval and management
|
||||||
|
//
|
||||||
|
// The Credentials is the primary method of getting access to and managing
|
||||||
|
// credentials Values. Using dependency injection retrieval of the credential
|
||||||
|
// values is handled by a object which satisfies the Provider interface.
|
||||||
|
//
|
||||||
|
// By default the Credentials.Get() will cache the successful result of a
|
||||||
|
// Provider's Retrieve() until Provider.IsExpired() returns true. At which
|
||||||
|
// point Credentials will call Provider's Retrieve() to get new credential Value.
|
||||||
|
//
|
||||||
|
// The Provider is responsible for determining when credentials Value have expired.
|
||||||
|
// It is also important to note that Credentials will always call Retrieve the
|
||||||
|
// first time Credentials.Get() is called.
|
||||||
|
//
|
||||||
|
// Example of using the environment variable credentials.
|
||||||
|
//
|
||||||
|
// creds := credentials.NewEnvCredentials()
|
||||||
|
//
|
||||||
|
// // Retrieve the credentials value
|
||||||
|
// credValue, err := creds.Get()
|
||||||
|
// if err != nil {
|
||||||
|
// // handle error
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example of forcing credentials to expire and be refreshed on the next Get().
|
||||||
|
// This may be helpful to proactively expire credentials and refresh them sooner
|
||||||
|
// than they would naturally expire on their own.
|
||||||
|
//
|
||||||
|
// creds := credentials.NewCredentials(&ec2rolecreds.EC2RoleProvider{})
|
||||||
|
// creds.Expire()
|
||||||
|
// credsValue, err := creds.Get()
|
||||||
|
// // New credentials will be retrieved instead of from cache.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Custom Provider
|
||||||
|
//
|
||||||
|
// Each Provider built into this package also provides a helper method to generate
|
||||||
|
// a Credentials pointer setup with the provider. To use a custom Provider just
|
||||||
|
// create a type which satisfies the Provider interface and pass it to the
|
||||||
|
// NewCredentials method.
|
||||||
|
//
|
||||||
|
// type MyProvider struct{}
|
||||||
|
// func (m *MyProvider) Retrieve() (Value, error) {...}
|
||||||
|
// func (m *MyProvider) IsExpired() bool {...}
|
||||||
|
//
|
||||||
|
// creds := credentials.NewCredentials(&MyProvider{})
|
||||||
|
// credValue, err := creds.Get()
|
||||||
|
//
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/sync/singleflight"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AnonymousCredentials is an empty Credential object that can be used as
|
||||||
|
// dummy placeholder credentials for requests that do not need signed.
|
||||||
|
//
|
||||||
|
// This Credentials can be used to configure a service to not sign requests
|
||||||
|
// when making service API calls. For example, when accessing public
|
||||||
|
// s3 buckets.
|
||||||
|
//
|
||||||
|
// svc := s3.New(session.Must(session.NewSession(&aws.Config{
|
||||||
|
// Credentials: credentials.AnonymousCredentials,
|
||||||
|
// })))
|
||||||
|
// // Access public S3 buckets.
|
||||||
|
var AnonymousCredentials = NewStaticCredentials("", "", "")
|
||||||
|
|
||||||
|
// A Value is the AWS credentials value for individual credential fields.
|
||||||
|
type Value struct {
|
||||||
|
// AWS Access key ID
|
||||||
|
AccessKeyID string
|
||||||
|
|
||||||
|
// AWS Secret Access Key
|
||||||
|
SecretAccessKey string
|
||||||
|
|
||||||
|
// AWS Session Token
|
||||||
|
SessionToken string
|
||||||
|
|
||||||
|
// Provider used to get credentials
|
||||||
|
ProviderName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasKeys returns if the credentials Value has both AccessKeyID and
|
||||||
|
// SecretAccessKey value set.
|
||||||
|
func (v Value) HasKeys() bool {
|
||||||
|
return len(v.AccessKeyID) != 0 && len(v.SecretAccessKey) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Provider is the interface for any component which will provide credentials
|
||||||
|
// Value. A provider is required to manage its own Expired state, and what to
|
||||||
|
// be expired means.
|
||||||
|
//
|
||||||
|
// The Provider should not need to implement its own mutexes, because
|
||||||
|
// that will be managed by Credentials.
|
||||||
|
type Provider interface {
|
||||||
|
// Retrieve returns nil if it successfully retrieved the value.
|
||||||
|
// Error is returned if the value were not obtainable, or empty.
|
||||||
|
Retrieve() (Value, error)
|
||||||
|
|
||||||
|
// IsExpired returns if the credentials are no longer valid, and need
|
||||||
|
// to be retrieved.
|
||||||
|
IsExpired() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProviderWithContext is a Provider that can retrieve credentials with a Context
|
||||||
|
type ProviderWithContext interface {
|
||||||
|
Provider
|
||||||
|
|
||||||
|
RetrieveWithContext(Context) (Value, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An Expirer is an interface that Providers can implement to expose the expiration
|
||||||
|
// time, if known. If the Provider cannot accurately provide this info,
|
||||||
|
// it should not implement this interface.
|
||||||
|
type Expirer interface {
|
||||||
|
// The time at which the credentials are no longer valid
|
||||||
|
ExpiresAt() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ErrorProvider is a stub credentials provider that always returns an error
|
||||||
|
// this is used by the SDK when construction a known provider is not possible
|
||||||
|
// due to an error.
|
||||||
|
type ErrorProvider struct {
|
||||||
|
// The error to be returned from Retrieve
|
||||||
|
Err error
|
||||||
|
|
||||||
|
// The provider name to set on the Retrieved returned Value
|
||||||
|
ProviderName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve will always return the error that the ErrorProvider was created with.
|
||||||
|
func (p ErrorProvider) Retrieve() (Value, error) {
|
||||||
|
return Value{ProviderName: p.ProviderName}, p.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired will always return not expired.
|
||||||
|
func (p ErrorProvider) IsExpired() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Expiry provides shared expiration logic to be used by credentials
|
||||||
|
// providers to implement expiry functionality.
|
||||||
|
//
|
||||||
|
// The best method to use this struct is as an anonymous field within the
|
||||||
|
// provider's struct.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// type EC2RoleProvider struct {
|
||||||
|
// Expiry
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
type Expiry struct {
|
||||||
|
// The date/time when to expire on
|
||||||
|
expiration time.Time
|
||||||
|
|
||||||
|
// If set will be used by IsExpired to determine the current time.
|
||||||
|
// Defaults to time.Now if CurrentTime is not set. Available for testing
|
||||||
|
// to be able to mock out the current time.
|
||||||
|
CurrentTime func() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetExpiration sets the expiration IsExpired will check when called.
|
||||||
|
//
|
||||||
|
// If window is greater than 0 the expiration time will be reduced by the
|
||||||
|
// window value.
|
||||||
|
//
|
||||||
|
// Using a window is helpful to trigger credentials to expire sooner than
|
||||||
|
// the expiration time given to ensure no requests are made with expired
|
||||||
|
// tokens.
|
||||||
|
func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) {
|
||||||
|
// Passed in expirations should have the monotonic clock values stripped.
|
||||||
|
// This ensures time comparisons will be based on wall-time.
|
||||||
|
e.expiration = expiration.Round(0)
|
||||||
|
if window > 0 {
|
||||||
|
e.expiration = e.expiration.Add(-window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns if the credentials are expired.
|
||||||
|
func (e *Expiry) IsExpired() bool {
|
||||||
|
curTime := e.CurrentTime
|
||||||
|
if curTime == nil {
|
||||||
|
curTime = time.Now
|
||||||
|
}
|
||||||
|
return e.expiration.Before(curTime())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpiresAt returns the expiration time of the credential
|
||||||
|
func (e *Expiry) ExpiresAt() time.Time {
|
||||||
|
return e.expiration
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Credentials provides concurrency safe retrieval of AWS credentials Value.
|
||||||
|
// Credentials will cache the credentials value until they expire. Once the value
|
||||||
|
// expires the next Get will attempt to retrieve valid credentials.
|
||||||
|
//
|
||||||
|
// Credentials is safe to use across multiple goroutines and will manage the
|
||||||
|
// synchronous state so the Providers do not need to implement their own
|
||||||
|
// synchronization.
|
||||||
|
//
|
||||||
|
// The first Credentials.Get() will always call Provider.Retrieve() to get the
|
||||||
|
// first instance of the credentials Value. All calls to Get() after that
|
||||||
|
// will return the cached credentials Value until IsExpired() returns true.
|
||||||
|
type Credentials struct {
|
||||||
|
sf singleflight.Group
|
||||||
|
|
||||||
|
m sync.RWMutex
|
||||||
|
creds Value
|
||||||
|
provider Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentials returns a pointer to a new Credentials with the provider set.
|
||||||
|
func NewCredentials(provider Provider) *Credentials {
|
||||||
|
c := &Credentials{
|
||||||
|
provider: provider,
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWithContext returns the credentials value, or error if the credentials
|
||||||
|
// Value failed to be retrieved. Will return early if the passed in context is
|
||||||
|
// canceled.
|
||||||
|
//
|
||||||
|
// Will return the cached credentials Value if it has not expired. If the
|
||||||
|
// credentials Value has expired the Provider's Retrieve() will be called
|
||||||
|
// to refresh the credentials.
|
||||||
|
//
|
||||||
|
// If Credentials.Expire() was called the credentials Value will be force
|
||||||
|
// expired, and the next call to Get() will cause them to be refreshed.
|
||||||
|
//
|
||||||
|
// Passed in Context is equivalent to aws.Context, and context.Context.
|
||||||
|
func (c *Credentials) GetWithContext(ctx Context) (Value, error) {
|
||||||
|
// Check if credentials are cached, and not expired.
|
||||||
|
select {
|
||||||
|
case curCreds, ok := <-c.asyncIsExpired():
|
||||||
|
// ok will only be true, of the credentials were not expired. ok will
|
||||||
|
// be false and have no value if the credentials are expired.
|
||||||
|
if ok {
|
||||||
|
return curCreds, nil
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
return Value{}, awserr.New("RequestCanceled",
|
||||||
|
"request context canceled", ctx.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot pass context down to the actual retrieve, because the first
|
||||||
|
// context would cancel the whole group when there is not direct
|
||||||
|
// association of items in the group.
|
||||||
|
resCh := c.sf.DoChan("", func() (interface{}, error) {
|
||||||
|
return c.singleRetrieve(&suppressedContext{ctx})
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case res := <-resCh:
|
||||||
|
return res.Val.(Value), res.Err
|
||||||
|
case <-ctx.Done():
|
||||||
|
return Value{}, awserr.New("RequestCanceled",
|
||||||
|
"request context canceled", ctx.Err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Credentials) singleRetrieve(ctx Context) (interface{}, error) {
|
||||||
|
c.m.Lock()
|
||||||
|
defer c.m.Unlock()
|
||||||
|
|
||||||
|
if curCreds := c.creds; !c.isExpiredLocked(curCreds) {
|
||||||
|
return curCreds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var creds Value
|
||||||
|
var err error
|
||||||
|
if p, ok := c.provider.(ProviderWithContext); ok {
|
||||||
|
creds, err = p.RetrieveWithContext(ctx)
|
||||||
|
} else {
|
||||||
|
creds, err = c.provider.Retrieve()
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
c.creds = creds
|
||||||
|
}
|
||||||
|
|
||||||
|
return creds, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the credentials value, or error if the credentials Value failed
|
||||||
|
// to be retrieved.
|
||||||
|
//
|
||||||
|
// Will return the cached credentials Value if it has not expired. If the
|
||||||
|
// credentials Value has expired the Provider's Retrieve() will be called
|
||||||
|
// to refresh the credentials.
|
||||||
|
//
|
||||||
|
// If Credentials.Expire() was called the credentials Value will be force
|
||||||
|
// expired, and the next call to Get() will cause them to be refreshed.
|
||||||
|
func (c *Credentials) Get() (Value, error) {
|
||||||
|
return c.GetWithContext(backgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expire expires the credentials and forces them to be retrieved on the
|
||||||
|
// next call to Get().
|
||||||
|
//
|
||||||
|
// This will override the Provider's expired state, and force Credentials
|
||||||
|
// to call the Provider's Retrieve().
|
||||||
|
func (c *Credentials) Expire() {
|
||||||
|
c.m.Lock()
|
||||||
|
defer c.m.Unlock()
|
||||||
|
|
||||||
|
c.creds = Value{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns if the credentials are no longer valid, and need
|
||||||
|
// to be retrieved.
|
||||||
|
//
|
||||||
|
// If the Credentials were forced to be expired with Expire() this will
|
||||||
|
// reflect that override.
|
||||||
|
func (c *Credentials) IsExpired() bool {
|
||||||
|
c.m.RLock()
|
||||||
|
defer c.m.RUnlock()
|
||||||
|
|
||||||
|
return c.isExpiredLocked(c.creds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// asyncIsExpired returns a channel of credentials Value. If the channel is
|
||||||
|
// closed the credentials are expired and credentials value are not empty.
|
||||||
|
func (c *Credentials) asyncIsExpired() <-chan Value {
|
||||||
|
ch := make(chan Value, 1)
|
||||||
|
go func() {
|
||||||
|
c.m.RLock()
|
||||||
|
defer c.m.RUnlock()
|
||||||
|
|
||||||
|
if curCreds := c.creds; !c.isExpiredLocked(curCreds) {
|
||||||
|
ch <- curCreds
|
||||||
|
}
|
||||||
|
|
||||||
|
close(ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// isExpiredLocked helper method wrapping the definition of expired credentials.
|
||||||
|
func (c *Credentials) isExpiredLocked(creds interface{}) bool {
|
||||||
|
return creds == nil || creds.(Value) == Value{} || c.provider.IsExpired()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpiresAt provides access to the functionality of the Expirer interface of
|
||||||
|
// the underlying Provider, if it supports that interface. Otherwise, it returns
|
||||||
|
// an error.
|
||||||
|
func (c *Credentials) ExpiresAt() (time.Time, error) {
|
||||||
|
c.m.RLock()
|
||||||
|
defer c.m.RUnlock()
|
||||||
|
|
||||||
|
expirer, ok := c.provider.(Expirer)
|
||||||
|
if !ok {
|
||||||
|
return time.Time{}, awserr.New("ProviderNotExpirer",
|
||||||
|
fmt.Sprintf("provider %s does not support ExpiresAt()",
|
||||||
|
c.creds.ProviderName),
|
||||||
|
nil)
|
||||||
|
}
|
||||||
|
if c.creds == (Value{}) {
|
||||||
|
// set expiration time to the distant past
|
||||||
|
return time.Time{}, nil
|
||||||
|
}
|
||||||
|
return expirer.ExpiresAt(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type suppressedContext struct {
|
||||||
|
Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *suppressedContext) Deadline() (deadline time.Time, ok bool) {
|
||||||
|
return time.Time{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *suppressedContext) Done() <-chan struct{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *suppressedContext) Err() error {
|
||||||
|
return nil
|
||||||
|
}
|
188
vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
generated
vendored
Normal file
188
vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
package ec2rolecreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/sdkuri"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProviderName provides a name of EC2Role provider
|
||||||
|
const ProviderName = "EC2RoleProvider"
|
||||||
|
|
||||||
|
// A EC2RoleProvider retrieves credentials from the EC2 service, and keeps track if
|
||||||
|
// those credentials are expired.
|
||||||
|
//
|
||||||
|
// Example how to configure the EC2RoleProvider with custom http Client, Endpoint
|
||||||
|
// or ExpiryWindow
|
||||||
|
//
|
||||||
|
// p := &ec2rolecreds.EC2RoleProvider{
|
||||||
|
// // Pass in a custom timeout to be used when requesting
|
||||||
|
// // IAM EC2 Role credentials.
|
||||||
|
// Client: ec2metadata.New(sess, aws.Config{
|
||||||
|
// HTTPClient: &http.Client{Timeout: 10 * time.Second},
|
||||||
|
// }),
|
||||||
|
//
|
||||||
|
// // Do not use early expiry of credentials. If a non zero value is
|
||||||
|
// // specified the credentials will be expired early
|
||||||
|
// ExpiryWindow: 0,
|
||||||
|
// }
|
||||||
|
type EC2RoleProvider struct {
|
||||||
|
credentials.Expiry
|
||||||
|
|
||||||
|
// Required EC2Metadata client to use when connecting to EC2 metadata service.
|
||||||
|
Client *ec2metadata.EC2Metadata
|
||||||
|
|
||||||
|
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||||
|
// the credentials actually expiring. This is beneficial so race conditions
|
||||||
|
// with expiring credentials do not cause request to fail unexpectedly
|
||||||
|
// due to ExpiredTokenException exceptions.
|
||||||
|
//
|
||||||
|
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
|
||||||
|
// 10 seconds before the credentials are actually expired.
|
||||||
|
//
|
||||||
|
// If ExpiryWindow is 0 or less it will be ignored.
|
||||||
|
ExpiryWindow time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentials returns a pointer to a new Credentials object wrapping
|
||||||
|
// the EC2RoleProvider. Takes a ConfigProvider to create a EC2Metadata client.
|
||||||
|
// The ConfigProvider is satisfied by the session.Session type.
|
||||||
|
func NewCredentials(c client.ConfigProvider, options ...func(*EC2RoleProvider)) *credentials.Credentials {
|
||||||
|
p := &EC2RoleProvider{
|
||||||
|
Client: ec2metadata.New(c),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials.NewCredentials(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping
|
||||||
|
// the EC2RoleProvider. Takes a EC2Metadata client to use when connecting to EC2
|
||||||
|
// metadata service.
|
||||||
|
func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*EC2RoleProvider)) *credentials.Credentials {
|
||||||
|
p := &EC2RoleProvider{
|
||||||
|
Client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials.NewCredentials(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve retrieves credentials from the EC2 service.
|
||||||
|
// Error will be returned if the request fails, or unable to extract
|
||||||
|
// the desired credentials.
|
||||||
|
func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
|
return m.RetrieveWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveWithContext retrieves credentials from the EC2 service.
|
||||||
|
// Error will be returned if the request fails, or unable to extract
|
||||||
|
// the desired credentials.
|
||||||
|
func (m *EC2RoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
||||||
|
credsList, err := requestCredList(ctx, m.Client)
|
||||||
|
if err != nil {
|
||||||
|
return credentials.Value{ProviderName: ProviderName}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(credsList) == 0 {
|
||||||
|
return credentials.Value{ProviderName: ProviderName}, awserr.New("EmptyEC2RoleList", "empty EC2 Role list", nil)
|
||||||
|
}
|
||||||
|
credsName := credsList[0]
|
||||||
|
|
||||||
|
roleCreds, err := requestCred(ctx, m.Client, credsName)
|
||||||
|
if err != nil {
|
||||||
|
return credentials.Value{ProviderName: ProviderName}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.SetExpiration(roleCreds.Expiration, m.ExpiryWindow)
|
||||||
|
|
||||||
|
return credentials.Value{
|
||||||
|
AccessKeyID: roleCreds.AccessKeyID,
|
||||||
|
SecretAccessKey: roleCreds.SecretAccessKey,
|
||||||
|
SessionToken: roleCreds.Token,
|
||||||
|
ProviderName: ProviderName,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A ec2RoleCredRespBody provides the shape for unmarshaling credential
|
||||||
|
// request responses.
|
||||||
|
type ec2RoleCredRespBody struct {
|
||||||
|
// Success State
|
||||||
|
Expiration time.Time
|
||||||
|
AccessKeyID string
|
||||||
|
SecretAccessKey string
|
||||||
|
Token string
|
||||||
|
|
||||||
|
// Error state
|
||||||
|
Code string
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
const iamSecurityCredsPath = "iam/security-credentials/"
|
||||||
|
|
||||||
|
// requestCredList requests a list of credentials from the EC2 service.
|
||||||
|
// If there are no credentials, or there is an error making or receiving the request
|
||||||
|
func requestCredList(ctx aws.Context, client *ec2metadata.EC2Metadata) ([]string, error) {
|
||||||
|
resp, err := client.GetMetadataWithContext(ctx, iamSecurityCredsPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, awserr.New("EC2RoleRequestError", "no EC2 instance role found", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
credsList := []string{}
|
||||||
|
s := bufio.NewScanner(strings.NewReader(resp))
|
||||||
|
for s.Scan() {
|
||||||
|
credsList = append(credsList, s.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.Err(); err != nil {
|
||||||
|
return nil, awserr.New(request.ErrCodeSerialization,
|
||||||
|
"failed to read EC2 instance role from metadata service", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return credsList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// requestCred requests the credentials for a specific credentials from the EC2 service.
|
||||||
|
//
|
||||||
|
// If the credentials cannot be found, or there is an error reading the response
|
||||||
|
// and error will be returned.
|
||||||
|
func requestCred(ctx aws.Context, client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) {
|
||||||
|
resp, err := client.GetMetadataWithContext(ctx, sdkuri.PathJoin(iamSecurityCredsPath, credsName))
|
||||||
|
if err != nil {
|
||||||
|
return ec2RoleCredRespBody{},
|
||||||
|
awserr.New("EC2RoleRequestError",
|
||||||
|
fmt.Sprintf("failed to get %s EC2 instance role credentials", credsName),
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
respCreds := ec2RoleCredRespBody{}
|
||||||
|
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&respCreds); err != nil {
|
||||||
|
return ec2RoleCredRespBody{},
|
||||||
|
awserr.New(request.ErrCodeSerialization,
|
||||||
|
fmt.Sprintf("failed to decode %s EC2 instance role credentials", credsName),
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if respCreds.Code != "Success" {
|
||||||
|
// If an error code was returned something failed requesting the role.
|
||||||
|
return ec2RoleCredRespBody{}, awserr.New(respCreds.Code, respCreds.Message, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return respCreds, nil
|
||||||
|
}
|
210
vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go
generated
vendored
Normal file
210
vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go
generated
vendored
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
// Package endpointcreds provides support for retrieving credentials from an
|
||||||
|
// arbitrary HTTP endpoint.
|
||||||
|
//
|
||||||
|
// The credentials endpoint Provider can receive both static and refreshable
|
||||||
|
// credentials that will expire. Credentials are static when an "Expiration"
|
||||||
|
// value is not provided in the endpoint's response.
|
||||||
|
//
|
||||||
|
// Static credentials will never expire once they have been retrieved. The format
|
||||||
|
// of the static credentials response:
|
||||||
|
// {
|
||||||
|
// "AccessKeyId" : "MUA...",
|
||||||
|
// "SecretAccessKey" : "/7PC5om....",
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Refreshable credentials will expire within the "ExpiryWindow" of the Expiration
|
||||||
|
// value in the response. The format of the refreshable credentials response:
|
||||||
|
// {
|
||||||
|
// "AccessKeyId" : "MUA...",
|
||||||
|
// "SecretAccessKey" : "/7PC5om....",
|
||||||
|
// "Token" : "AQoDY....=",
|
||||||
|
// "Expiration" : "2016-02-25T06:03:31Z"
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Errors should be returned in the following format and only returned with 400
|
||||||
|
// or 500 HTTP status codes.
|
||||||
|
// {
|
||||||
|
// "code": "ErrorCode",
|
||||||
|
// "message": "Helpful error message."
|
||||||
|
// }
|
||||||
|
package endpointcreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol/json/jsonutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProviderName is the name of the credentials provider.
|
||||||
|
const ProviderName = `CredentialsEndpointProvider`
|
||||||
|
|
||||||
|
// Provider satisfies the credentials.Provider interface, and is a client to
|
||||||
|
// retrieve credentials from an arbitrary endpoint.
|
||||||
|
type Provider struct {
|
||||||
|
staticCreds bool
|
||||||
|
credentials.Expiry
|
||||||
|
|
||||||
|
// Requires a AWS Client to make HTTP requests to the endpoint with.
|
||||||
|
// the Endpoint the request will be made to is provided by the aws.Config's
|
||||||
|
// Endpoint value.
|
||||||
|
Client *client.Client
|
||||||
|
|
||||||
|
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||||
|
// the credentials actually expiring. This is beneficial so race conditions
|
||||||
|
// with expiring credentials do not cause request to fail unexpectedly
|
||||||
|
// due to ExpiredTokenException exceptions.
|
||||||
|
//
|
||||||
|
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
|
||||||
|
// 10 seconds before the credentials are actually expired.
|
||||||
|
//
|
||||||
|
// If ExpiryWindow is 0 or less it will be ignored.
|
||||||
|
ExpiryWindow time.Duration
|
||||||
|
|
||||||
|
// Optional authorization token value if set will be used as the value of
|
||||||
|
// the Authorization header of the endpoint credential request.
|
||||||
|
AuthorizationToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProviderClient returns a credentials Provider for retrieving AWS credentials
|
||||||
|
// from arbitrary endpoint.
|
||||||
|
func NewProviderClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) credentials.Provider {
|
||||||
|
p := &Provider{
|
||||||
|
Client: client.New(
|
||||||
|
cfg,
|
||||||
|
metadata.ClientInfo{
|
||||||
|
ServiceName: "CredentialsEndpoint",
|
||||||
|
Endpoint: endpoint,
|
||||||
|
},
|
||||||
|
handlers,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Client.Handlers.Unmarshal.PushBack(unmarshalHandler)
|
||||||
|
p.Client.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||||
|
p.Client.Handlers.Validate.Clear()
|
||||||
|
p.Client.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentialsClient returns a pointer to a new Credentials object
|
||||||
|
// wrapping the endpoint credentials Provider.
|
||||||
|
func NewCredentialsClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) *credentials.Credentials {
|
||||||
|
return credentials.NewCredentials(NewProviderClient(cfg, handlers, endpoint, options...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns true if the credentials retrieved are expired, or not yet
|
||||||
|
// retrieved.
|
||||||
|
func (p *Provider) IsExpired() bool {
|
||||||
|
if p.staticCreds {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return p.Expiry.IsExpired()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve will attempt to request the credentials from the endpoint the Provider
|
||||||
|
// was configured for. And error will be returned if the retrieval fails.
|
||||||
|
func (p *Provider) Retrieve() (credentials.Value, error) {
|
||||||
|
return p.RetrieveWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveWithContext will attempt to request the credentials from the endpoint the Provider
|
||||||
|
// was configured for. And error will be returned if the retrieval fails.
|
||||||
|
func (p *Provider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
||||||
|
resp, err := p.getCredentials(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return credentials.Value{ProviderName: ProviderName},
|
||||||
|
awserr.New("CredentialsEndpointError", "failed to load credentials", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Expiration != nil {
|
||||||
|
p.SetExpiration(*resp.Expiration, p.ExpiryWindow)
|
||||||
|
} else {
|
||||||
|
p.staticCreds = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials.Value{
|
||||||
|
AccessKeyID: resp.AccessKeyID,
|
||||||
|
SecretAccessKey: resp.SecretAccessKey,
|
||||||
|
SessionToken: resp.Token,
|
||||||
|
ProviderName: ProviderName,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type getCredentialsOutput struct {
|
||||||
|
Expiration *time.Time
|
||||||
|
AccessKeyID string
|
||||||
|
SecretAccessKey string
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorOutput struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) getCredentials(ctx aws.Context) (*getCredentialsOutput, error) {
|
||||||
|
op := &request.Operation{
|
||||||
|
Name: "GetCredentials",
|
||||||
|
HTTPMethod: "GET",
|
||||||
|
}
|
||||||
|
|
||||||
|
out := &getCredentialsOutput{}
|
||||||
|
req := p.Client.NewRequest(op, nil, out)
|
||||||
|
req.SetContext(ctx)
|
||||||
|
req.HTTPRequest.Header.Set("Accept", "application/json")
|
||||||
|
if authToken := p.AuthorizationToken; len(authToken) != 0 {
|
||||||
|
req.HTTPRequest.Header.Set("Authorization", authToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, req.Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateEndpointHandler(r *request.Request) {
|
||||||
|
if len(r.ClientInfo.Endpoint) == 0 {
|
||||||
|
r.Error = aws.ErrMissingEndpoint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalHandler(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
|
||||||
|
out := r.Data.(*getCredentialsOutput)
|
||||||
|
if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&out); err != nil {
|
||||||
|
r.Error = awserr.New(request.ErrCodeSerialization,
|
||||||
|
"failed to decode endpoint credentials",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalError(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
|
||||||
|
var errOut errorOutput
|
||||||
|
err := jsonutil.UnmarshalJSONError(&errOut, r.HTTPResponse.Body)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.NewRequestFailure(
|
||||||
|
awserr.New(request.ErrCodeSerialization,
|
||||||
|
"failed to decode error message", err),
|
||||||
|
r.HTTPResponse.StatusCode,
|
||||||
|
r.RequestID,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response body format is not consistent between metadata endpoints.
|
||||||
|
// Grab the error message as a string and include that as the source error
|
||||||
|
r.Error = awserr.New(errOut.Code, errOut.Message, nil)
|
||||||
|
}
|
74
vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go
generated
vendored
Normal file
74
vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EnvProviderName provides a name of Env provider
|
||||||
|
const EnvProviderName = "EnvProvider"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be
|
||||||
|
// found in the process's environment.
|
||||||
|
ErrAccessKeyIDNotFound = awserr.New("EnvAccessKeyNotFound", "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment", nil)
|
||||||
|
|
||||||
|
// ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key
|
||||||
|
// can't be found in the process's environment.
|
||||||
|
ErrSecretAccessKeyNotFound = awserr.New("EnvSecretNotFound", "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment", nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
// A EnvProvider retrieves credentials from the environment variables of the
|
||||||
|
// running process. Environment credentials never expire.
|
||||||
|
//
|
||||||
|
// Environment variables used:
|
||||||
|
//
|
||||||
|
// * Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY
|
||||||
|
//
|
||||||
|
// * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY
|
||||||
|
type EnvProvider struct {
|
||||||
|
retrieved bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEnvCredentials returns a pointer to a new Credentials object
|
||||||
|
// wrapping the environment variable provider.
|
||||||
|
func NewEnvCredentials() *Credentials {
|
||||||
|
return NewCredentials(&EnvProvider{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve retrieves the keys from the environment.
|
||||||
|
func (e *EnvProvider) Retrieve() (Value, error) {
|
||||||
|
e.retrieved = false
|
||||||
|
|
||||||
|
id := os.Getenv("AWS_ACCESS_KEY_ID")
|
||||||
|
if id == "" {
|
||||||
|
id = os.Getenv("AWS_ACCESS_KEY")
|
||||||
|
}
|
||||||
|
|
||||||
|
secret := os.Getenv("AWS_SECRET_ACCESS_KEY")
|
||||||
|
if secret == "" {
|
||||||
|
secret = os.Getenv("AWS_SECRET_KEY")
|
||||||
|
}
|
||||||
|
|
||||||
|
if id == "" {
|
||||||
|
return Value{ProviderName: EnvProviderName}, ErrAccessKeyIDNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if secret == "" {
|
||||||
|
return Value{ProviderName: EnvProviderName}, ErrSecretAccessKeyNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
e.retrieved = true
|
||||||
|
return Value{
|
||||||
|
AccessKeyID: id,
|
||||||
|
SecretAccessKey: secret,
|
||||||
|
SessionToken: os.Getenv("AWS_SESSION_TOKEN"),
|
||||||
|
ProviderName: EnvProviderName,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns if the credentials have been retrieved.
|
||||||
|
func (e *EnvProvider) IsExpired() bool {
|
||||||
|
return !e.retrieved
|
||||||
|
}
|
12
vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini
generated
vendored
Normal file
12
vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[default]
|
||||||
|
aws_access_key_id = accessKey
|
||||||
|
aws_secret_access_key = secret
|
||||||
|
aws_session_token = token
|
||||||
|
|
||||||
|
[no_token]
|
||||||
|
aws_access_key_id = accessKey
|
||||||
|
aws_secret_access_key = secret
|
||||||
|
|
||||||
|
[with_colon]
|
||||||
|
aws_access_key_id: accessKey
|
||||||
|
aws_secret_access_key: secret
|
426
vendor/github.com/aws/aws-sdk-go/aws/credentials/processcreds/provider.go
generated
vendored
Normal file
426
vendor/github.com/aws/aws-sdk-go/aws/credentials/processcreds/provider.go
generated
vendored
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
/*
|
||||||
|
Package processcreds is a credential Provider to retrieve `credential_process`
|
||||||
|
credentials.
|
||||||
|
|
||||||
|
WARNING: The following describes a method of sourcing credentials from an external
|
||||||
|
process. This can potentially be dangerous, so proceed with caution. Other
|
||||||
|
credential providers should be preferred if at all possible. If using this
|
||||||
|
option, you should make sure that the config file is as locked down as possible
|
||||||
|
using security best practices for your operating system.
|
||||||
|
|
||||||
|
You can use credentials from a `credential_process` in a variety of ways.
|
||||||
|
|
||||||
|
One way is to setup your shared config file, located in the default
|
||||||
|
location, with the `credential_process` key and the command you want to be
|
||||||
|
called. You also need to set the AWS_SDK_LOAD_CONFIG environment variable
|
||||||
|
(e.g., `export AWS_SDK_LOAD_CONFIG=1`) to use the shared config file.
|
||||||
|
|
||||||
|
[default]
|
||||||
|
credential_process = /command/to/call
|
||||||
|
|
||||||
|
Creating a new session will use the credential process to retrieve credentials.
|
||||||
|
NOTE: If there are credentials in the profile you are using, the credential
|
||||||
|
process will not be used.
|
||||||
|
|
||||||
|
// Initialize a session to load credentials.
|
||||||
|
sess, _ := session.NewSession(&aws.Config{
|
||||||
|
Region: aws.String("us-east-1")},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create S3 service client to use the credentials.
|
||||||
|
svc := s3.New(sess)
|
||||||
|
|
||||||
|
Another way to use the `credential_process` method is by using
|
||||||
|
`credentials.NewCredentials()` and providing a command to be executed to
|
||||||
|
retrieve credentials:
|
||||||
|
|
||||||
|
// Create credentials using the ProcessProvider.
|
||||||
|
creds := processcreds.NewCredentials("/path/to/command")
|
||||||
|
|
||||||
|
// Create service client value configured for credentials.
|
||||||
|
svc := s3.New(sess, &aws.Config{Credentials: creds})
|
||||||
|
|
||||||
|
You can set a non-default timeout for the `credential_process` with another
|
||||||
|
constructor, `credentials.NewCredentialsTimeout()`, providing the timeout. To
|
||||||
|
set a one minute timeout:
|
||||||
|
|
||||||
|
// Create credentials using the ProcessProvider.
|
||||||
|
creds := processcreds.NewCredentialsTimeout(
|
||||||
|
"/path/to/command",
|
||||||
|
time.Duration(500) * time.Millisecond)
|
||||||
|
|
||||||
|
If you need more control, you can set any configurable options in the
|
||||||
|
credentials using one or more option functions. For example, you can set a two
|
||||||
|
minute timeout, a credential duration of 60 minutes, and a maximum stdout
|
||||||
|
buffer size of 2k.
|
||||||
|
|
||||||
|
creds := processcreds.NewCredentials(
|
||||||
|
"/path/to/command",
|
||||||
|
func(opt *ProcessProvider) {
|
||||||
|
opt.Timeout = time.Duration(2) * time.Minute
|
||||||
|
opt.Duration = time.Duration(60) * time.Minute
|
||||||
|
opt.MaxBufSize = 2048
|
||||||
|
})
|
||||||
|
|
||||||
|
You can also use your own `exec.Cmd`:
|
||||||
|
|
||||||
|
// Create an exec.Cmd
|
||||||
|
myCommand := exec.Command("/path/to/command")
|
||||||
|
|
||||||
|
// Create credentials using your exec.Cmd and custom timeout
|
||||||
|
creds := processcreds.NewCredentialsCommand(
|
||||||
|
myCommand,
|
||||||
|
func(opt *processcreds.ProcessProvider) {
|
||||||
|
opt.Timeout = time.Duration(1) * time.Second
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
package processcreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/sdkio"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ProviderName is the name this credentials provider will label any
|
||||||
|
// returned credentials Value with.
|
||||||
|
ProviderName = `ProcessProvider`
|
||||||
|
|
||||||
|
// ErrCodeProcessProviderParse error parsing process output
|
||||||
|
ErrCodeProcessProviderParse = "ProcessProviderParseError"
|
||||||
|
|
||||||
|
// ErrCodeProcessProviderVersion version error in output
|
||||||
|
ErrCodeProcessProviderVersion = "ProcessProviderVersionError"
|
||||||
|
|
||||||
|
// ErrCodeProcessProviderRequired required attribute missing in output
|
||||||
|
ErrCodeProcessProviderRequired = "ProcessProviderRequiredError"
|
||||||
|
|
||||||
|
// ErrCodeProcessProviderExecution execution of command failed
|
||||||
|
ErrCodeProcessProviderExecution = "ProcessProviderExecutionError"
|
||||||
|
|
||||||
|
// errMsgProcessProviderTimeout process took longer than allowed
|
||||||
|
errMsgProcessProviderTimeout = "credential process timed out"
|
||||||
|
|
||||||
|
// errMsgProcessProviderProcess process error
|
||||||
|
errMsgProcessProviderProcess = "error in credential_process"
|
||||||
|
|
||||||
|
// errMsgProcessProviderParse problem parsing output
|
||||||
|
errMsgProcessProviderParse = "parse failed of credential_process output"
|
||||||
|
|
||||||
|
// errMsgProcessProviderVersion version error in output
|
||||||
|
errMsgProcessProviderVersion = "wrong version in process output (not 1)"
|
||||||
|
|
||||||
|
// errMsgProcessProviderMissKey missing access key id in output
|
||||||
|
errMsgProcessProviderMissKey = "missing AccessKeyId in process output"
|
||||||
|
|
||||||
|
// errMsgProcessProviderMissSecret missing secret acess key in output
|
||||||
|
errMsgProcessProviderMissSecret = "missing SecretAccessKey in process output"
|
||||||
|
|
||||||
|
// errMsgProcessProviderPrepareCmd prepare of command failed
|
||||||
|
errMsgProcessProviderPrepareCmd = "failed to prepare command"
|
||||||
|
|
||||||
|
// errMsgProcessProviderEmptyCmd command must not be empty
|
||||||
|
errMsgProcessProviderEmptyCmd = "command must not be empty"
|
||||||
|
|
||||||
|
// errMsgProcessProviderPipe failed to initialize pipe
|
||||||
|
errMsgProcessProviderPipe = "failed to initialize pipe"
|
||||||
|
|
||||||
|
// DefaultDuration is the default amount of time in minutes that the
|
||||||
|
// credentials will be valid for.
|
||||||
|
DefaultDuration = time.Duration(15) * time.Minute
|
||||||
|
|
||||||
|
// DefaultBufSize limits buffer size from growing to an enormous
|
||||||
|
// amount due to a faulty process.
|
||||||
|
DefaultBufSize = int(8 * sdkio.KibiByte)
|
||||||
|
|
||||||
|
// DefaultTimeout default limit on time a process can run.
|
||||||
|
DefaultTimeout = time.Duration(1) * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessProvider satisfies the credentials.Provider interface, and is a
|
||||||
|
// client to retrieve credentials from a process.
|
||||||
|
type ProcessProvider struct {
|
||||||
|
staticCreds bool
|
||||||
|
credentials.Expiry
|
||||||
|
originalCommand []string
|
||||||
|
|
||||||
|
// Expiry duration of the credentials. Defaults to 15 minutes if not set.
|
||||||
|
Duration time.Duration
|
||||||
|
|
||||||
|
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||||
|
// the credentials actually expiring. This is beneficial so race conditions
|
||||||
|
// with expiring credentials do not cause request to fail unexpectedly
|
||||||
|
// due to ExpiredTokenException exceptions.
|
||||||
|
//
|
||||||
|
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
|
||||||
|
// 10 seconds before the credentials are actually expired.
|
||||||
|
//
|
||||||
|
// If ExpiryWindow is 0 or less it will be ignored.
|
||||||
|
ExpiryWindow time.Duration
|
||||||
|
|
||||||
|
// A string representing an os command that should return a JSON with
|
||||||
|
// credential information.
|
||||||
|
command *exec.Cmd
|
||||||
|
|
||||||
|
// MaxBufSize limits memory usage from growing to an enormous
|
||||||
|
// amount due to a faulty process.
|
||||||
|
MaxBufSize int
|
||||||
|
|
||||||
|
// Timeout limits the time a process can run.
|
||||||
|
Timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentials returns a pointer to a new Credentials object wrapping the
|
||||||
|
// ProcessProvider. The credentials will expire every 15 minutes by default.
|
||||||
|
func NewCredentials(command string, options ...func(*ProcessProvider)) *credentials.Credentials {
|
||||||
|
p := &ProcessProvider{
|
||||||
|
command: exec.Command(command),
|
||||||
|
Duration: DefaultDuration,
|
||||||
|
Timeout: DefaultTimeout,
|
||||||
|
MaxBufSize: DefaultBufSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials.NewCredentials(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentialsTimeout returns a pointer to a new Credentials object with
|
||||||
|
// the specified command and timeout, and default duration and max buffer size.
|
||||||
|
func NewCredentialsTimeout(command string, timeout time.Duration) *credentials.Credentials {
|
||||||
|
p := NewCredentials(command, func(opt *ProcessProvider) {
|
||||||
|
opt.Timeout = timeout
|
||||||
|
})
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentialsCommand returns a pointer to a new Credentials object with
|
||||||
|
// the specified command, and default timeout, duration and max buffer size.
|
||||||
|
func NewCredentialsCommand(command *exec.Cmd, options ...func(*ProcessProvider)) *credentials.Credentials {
|
||||||
|
p := &ProcessProvider{
|
||||||
|
command: command,
|
||||||
|
Duration: DefaultDuration,
|
||||||
|
Timeout: DefaultTimeout,
|
||||||
|
MaxBufSize: DefaultBufSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials.NewCredentials(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
type credentialProcessResponse struct {
|
||||||
|
Version int
|
||||||
|
AccessKeyID string `json:"AccessKeyId"`
|
||||||
|
SecretAccessKey string
|
||||||
|
SessionToken string
|
||||||
|
Expiration *time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve executes the 'credential_process' and returns the credentials.
|
||||||
|
func (p *ProcessProvider) Retrieve() (credentials.Value, error) {
|
||||||
|
out, err := p.executeCredentialProcess()
|
||||||
|
if err != nil {
|
||||||
|
return credentials.Value{ProviderName: ProviderName}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize and validate response
|
||||||
|
resp := &credentialProcessResponse{}
|
||||||
|
if err = json.Unmarshal(out, resp); err != nil {
|
||||||
|
return credentials.Value{ProviderName: ProviderName}, awserr.New(
|
||||||
|
ErrCodeProcessProviderParse,
|
||||||
|
fmt.Sprintf("%s: %s", errMsgProcessProviderParse, string(out)),
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Version != 1 {
|
||||||
|
return credentials.Value{ProviderName: ProviderName}, awserr.New(
|
||||||
|
ErrCodeProcessProviderVersion,
|
||||||
|
errMsgProcessProviderVersion,
|
||||||
|
nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.AccessKeyID) == 0 {
|
||||||
|
return credentials.Value{ProviderName: ProviderName}, awserr.New(
|
||||||
|
ErrCodeProcessProviderRequired,
|
||||||
|
errMsgProcessProviderMissKey,
|
||||||
|
nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.SecretAccessKey) == 0 {
|
||||||
|
return credentials.Value{ProviderName: ProviderName}, awserr.New(
|
||||||
|
ErrCodeProcessProviderRequired,
|
||||||
|
errMsgProcessProviderMissSecret,
|
||||||
|
nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle expiration
|
||||||
|
p.staticCreds = resp.Expiration == nil
|
||||||
|
if resp.Expiration != nil {
|
||||||
|
p.SetExpiration(*resp.Expiration, p.ExpiryWindow)
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials.Value{
|
||||||
|
ProviderName: ProviderName,
|
||||||
|
AccessKeyID: resp.AccessKeyID,
|
||||||
|
SecretAccessKey: resp.SecretAccessKey,
|
||||||
|
SessionToken: resp.SessionToken,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns true if the credentials retrieved are expired, or not yet
|
||||||
|
// retrieved.
|
||||||
|
func (p *ProcessProvider) IsExpired() bool {
|
||||||
|
if p.staticCreds {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return p.Expiry.IsExpired()
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepareCommand prepares the command to be executed.
|
||||||
|
func (p *ProcessProvider) prepareCommand() error {
|
||||||
|
|
||||||
|
var cmdArgs []string
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
cmdArgs = []string{"cmd.exe", "/C"}
|
||||||
|
} else {
|
||||||
|
cmdArgs = []string{"sh", "-c"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p.originalCommand) == 0 {
|
||||||
|
p.originalCommand = make([]string, len(p.command.Args))
|
||||||
|
copy(p.originalCommand, p.command.Args)
|
||||||
|
|
||||||
|
// check for empty command because it succeeds
|
||||||
|
if len(strings.TrimSpace(p.originalCommand[0])) < 1 {
|
||||||
|
return awserr.New(
|
||||||
|
ErrCodeProcessProviderExecution,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"%s: %s",
|
||||||
|
errMsgProcessProviderPrepareCmd,
|
||||||
|
errMsgProcessProviderEmptyCmd),
|
||||||
|
nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdArgs = append(cmdArgs, p.originalCommand...)
|
||||||
|
p.command = exec.Command(cmdArgs[0], cmdArgs[1:]...)
|
||||||
|
p.command.Env = os.Environ()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeCredentialProcess starts the credential process on the OS and
|
||||||
|
// returns the results or an error.
|
||||||
|
func (p *ProcessProvider) executeCredentialProcess() ([]byte, error) {
|
||||||
|
|
||||||
|
if err := p.prepareCommand(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the pipes
|
||||||
|
outReadPipe, outWritePipe, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, awserr.New(
|
||||||
|
ErrCodeProcessProviderExecution,
|
||||||
|
errMsgProcessProviderPipe,
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.command.Stderr = os.Stderr // display stderr on console for MFA
|
||||||
|
p.command.Stdout = outWritePipe // get creds json on process's stdout
|
||||||
|
p.command.Stdin = os.Stdin // enable stdin for MFA
|
||||||
|
|
||||||
|
output := bytes.NewBuffer(make([]byte, 0, p.MaxBufSize))
|
||||||
|
|
||||||
|
stdoutCh := make(chan error, 1)
|
||||||
|
go readInput(
|
||||||
|
io.LimitReader(outReadPipe, int64(p.MaxBufSize)),
|
||||||
|
output,
|
||||||
|
stdoutCh)
|
||||||
|
|
||||||
|
execCh := make(chan error, 1)
|
||||||
|
go executeCommand(*p.command, execCh)
|
||||||
|
|
||||||
|
finished := false
|
||||||
|
var errors []error
|
||||||
|
for !finished {
|
||||||
|
select {
|
||||||
|
case readError := <-stdoutCh:
|
||||||
|
errors = appendError(errors, readError)
|
||||||
|
finished = true
|
||||||
|
case execError := <-execCh:
|
||||||
|
err := outWritePipe.Close()
|
||||||
|
errors = appendError(errors, err)
|
||||||
|
errors = appendError(errors, execError)
|
||||||
|
if errors != nil {
|
||||||
|
return output.Bytes(), awserr.NewBatchError(
|
||||||
|
ErrCodeProcessProviderExecution,
|
||||||
|
errMsgProcessProviderProcess,
|
||||||
|
errors)
|
||||||
|
}
|
||||||
|
case <-time.After(p.Timeout):
|
||||||
|
finished = true
|
||||||
|
return output.Bytes(), awserr.NewBatchError(
|
||||||
|
ErrCodeProcessProviderExecution,
|
||||||
|
errMsgProcessProviderTimeout,
|
||||||
|
errors) // errors can be nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out := output.Bytes()
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// windows adds slashes to quotes
|
||||||
|
out = []byte(strings.Replace(string(out), `\"`, `"`, -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendError conveniently checks for nil before appending slice
|
||||||
|
func appendError(errors []error, err error) []error {
|
||||||
|
if err != nil {
|
||||||
|
return append(errors, err)
|
||||||
|
}
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeCommand(cmd exec.Cmd, exec chan error) {
|
||||||
|
// Start the command
|
||||||
|
err := cmd.Start()
|
||||||
|
if err == nil {
|
||||||
|
err = cmd.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
exec <- err
|
||||||
|
}
|
||||||
|
|
||||||
|
func readInput(r io.Reader, w io.Writer, read chan error) {
|
||||||
|
tee := io.TeeReader(r, w)
|
||||||
|
|
||||||
|
_, err := ioutil.ReadAll(tee)
|
||||||
|
|
||||||
|
if err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
read <- err // will only arrive here when write end of pipe is closed
|
||||||
|
}
|
151
vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go
generated
vendored
Normal file
151
vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/ini"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/shareddefaults"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SharedCredsProviderName provides a name of SharedCreds provider
|
||||||
|
const SharedCredsProviderName = "SharedCredentialsProvider"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found.
|
||||||
|
ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
// A SharedCredentialsProvider retrieves access key pair (access key ID,
|
||||||
|
// secret access key, and session token if present) credentials from the current
|
||||||
|
// user's home directory, and keeps track if those credentials are expired.
|
||||||
|
//
|
||||||
|
// Profile ini file example: $HOME/.aws/credentials
|
||||||
|
type SharedCredentialsProvider struct {
|
||||||
|
// Path to the shared credentials file.
|
||||||
|
//
|
||||||
|
// If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the
|
||||||
|
// env value is empty will default to current user's home directory.
|
||||||
|
// Linux/OSX: "$HOME/.aws/credentials"
|
||||||
|
// Windows: "%USERPROFILE%\.aws\credentials"
|
||||||
|
Filename string
|
||||||
|
|
||||||
|
// AWS Profile to extract credentials from the shared credentials file. If empty
|
||||||
|
// will default to environment variable "AWS_PROFILE" or "default" if
|
||||||
|
// environment variable is also not set.
|
||||||
|
Profile string
|
||||||
|
|
||||||
|
// retrieved states if the credentials have been successfully retrieved.
|
||||||
|
retrieved bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSharedCredentials returns a pointer to a new Credentials object
|
||||||
|
// wrapping the Profile file provider.
|
||||||
|
func NewSharedCredentials(filename, profile string) *Credentials {
|
||||||
|
return NewCredentials(&SharedCredentialsProvider{
|
||||||
|
Filename: filename,
|
||||||
|
Profile: profile,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve reads and extracts the shared credentials from the current
|
||||||
|
// users home directory.
|
||||||
|
func (p *SharedCredentialsProvider) Retrieve() (Value, error) {
|
||||||
|
p.retrieved = false
|
||||||
|
|
||||||
|
filename, err := p.filename()
|
||||||
|
if err != nil {
|
||||||
|
return Value{ProviderName: SharedCredsProviderName}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
creds, err := loadProfile(filename, p.profile())
|
||||||
|
if err != nil {
|
||||||
|
return Value{ProviderName: SharedCredsProviderName}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.retrieved = true
|
||||||
|
return creds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns if the shared credentials have expired.
|
||||||
|
func (p *SharedCredentialsProvider) IsExpired() bool {
|
||||||
|
return !p.retrieved
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadProfiles loads from the file pointed to by shared credentials filename for profile.
|
||||||
|
// The credentials retrieved from the profile will be returned or error. Error will be
|
||||||
|
// returned if it fails to read from the file, or the data is invalid.
|
||||||
|
func loadProfile(filename, profile string) (Value, error) {
|
||||||
|
config, err := ini.OpenFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to load shared credentials file", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
iniProfile, ok := config.GetSection(profile)
|
||||||
|
if !ok {
|
||||||
|
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to get profile", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
id := iniProfile.String("aws_access_key_id")
|
||||||
|
if len(id) == 0 {
|
||||||
|
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsAccessKey",
|
||||||
|
fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename),
|
||||||
|
nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
secret := iniProfile.String("aws_secret_access_key")
|
||||||
|
if len(secret) == 0 {
|
||||||
|
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsSecret",
|
||||||
|
fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename),
|
||||||
|
nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to empty string if not found
|
||||||
|
token := iniProfile.String("aws_session_token")
|
||||||
|
|
||||||
|
return Value{
|
||||||
|
AccessKeyID: id,
|
||||||
|
SecretAccessKey: secret,
|
||||||
|
SessionToken: token,
|
||||||
|
ProviderName: SharedCredsProviderName,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// filename returns the filename to use to read AWS shared credentials.
|
||||||
|
//
|
||||||
|
// Will return an error if the user's home directory path cannot be found.
|
||||||
|
func (p *SharedCredentialsProvider) filename() (string, error) {
|
||||||
|
if len(p.Filename) != 0 {
|
||||||
|
return p.Filename, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); len(p.Filename) != 0 {
|
||||||
|
return p.Filename, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if home := shareddefaults.UserHomeDir(); len(home) == 0 {
|
||||||
|
// Backwards compatibility of home directly not found error being returned.
|
||||||
|
// This error is too verbose, failure when opening the file would of been
|
||||||
|
// a better error to return.
|
||||||
|
return "", ErrSharedCredentialsHomeNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Filename = shareddefaults.SharedCredentialsFilename()
|
||||||
|
|
||||||
|
return p.Filename, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// profile returns the AWS shared credentials profile. If empty will read
|
||||||
|
// environment variable "AWS_PROFILE". If that is not set profile will
|
||||||
|
// return "default".
|
||||||
|
func (p *SharedCredentialsProvider) profile() string {
|
||||||
|
if p.Profile == "" {
|
||||||
|
p.Profile = os.Getenv("AWS_PROFILE")
|
||||||
|
}
|
||||||
|
if p.Profile == "" {
|
||||||
|
p.Profile = "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.Profile
|
||||||
|
}
|
60
vendor/github.com/aws/aws-sdk-go/aws/credentials/ssocreds/doc.go
generated
vendored
Normal file
60
vendor/github.com/aws/aws-sdk-go/aws/credentials/ssocreds/doc.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Package ssocreds provides a credential provider for retrieving temporary AWS credentials using an SSO access token.
|
||||||
|
//
|
||||||
|
// IMPORTANT: The provider in this package does not initiate or perform the AWS SSO login flow. The SDK provider
|
||||||
|
// expects that you have already performed the SSO login flow using AWS CLI using the "aws sso login" command, or by
|
||||||
|
// some other mechanism. The provider must find a valid non-expired access token for the AWS SSO user portal URL in
|
||||||
|
// ~/.aws/sso/cache. If a cached token is not found, it is expired, or the file is malformed an error will be returned.
|
||||||
|
//
|
||||||
|
// Loading AWS SSO credentials with the AWS shared configuration file
|
||||||
|
//
|
||||||
|
// You can use configure AWS SSO credentials from the AWS shared configuration file by
|
||||||
|
// providing the specifying the required keys in the profile:
|
||||||
|
//
|
||||||
|
// sso_account_id
|
||||||
|
// sso_region
|
||||||
|
// sso_role_name
|
||||||
|
// sso_start_url
|
||||||
|
//
|
||||||
|
// For example, the following defines a profile "devsso" and specifies the AWS SSO parameters that defines the target
|
||||||
|
// account, role, sign-on portal, and the region where the user portal is located. Note: all SSO arguments must be
|
||||||
|
// provided, or an error will be returned.
|
||||||
|
//
|
||||||
|
// [profile devsso]
|
||||||
|
// sso_start_url = https://my-sso-portal.awsapps.com/start
|
||||||
|
// sso_role_name = SSOReadOnlyRole
|
||||||
|
// sso_region = us-east-1
|
||||||
|
// sso_account_id = 123456789012
|
||||||
|
//
|
||||||
|
// Using the config module, you can load the AWS SDK shared configuration, and specify that this profile be used to
|
||||||
|
// retrieve credentials. For example:
|
||||||
|
//
|
||||||
|
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||||
|
// SharedConfigState: session.SharedConfigEnable,
|
||||||
|
// Profile: "devsso",
|
||||||
|
// })
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Programmatically loading AWS SSO credentials directly
|
||||||
|
//
|
||||||
|
// You can programmatically construct the AWS SSO Provider in your application, and provide the necessary information
|
||||||
|
// to load and retrieve temporary credentials using an access token from ~/.aws/sso/cache.
|
||||||
|
//
|
||||||
|
// svc := sso.New(sess, &aws.Config{
|
||||||
|
// Region: aws.String("us-west-2"), // Client Region must correspond to the AWS SSO user portal region
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// provider := ssocreds.NewCredentialsWithClient(svc, "123456789012", "SSOReadOnlyRole", "https://my-sso-portal.awsapps.com/start")
|
||||||
|
//
|
||||||
|
// credentials, err := provider.Get()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Additional Resources
|
||||||
|
//
|
||||||
|
// Configuring the AWS CLI to use AWS Single Sign-On: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html
|
||||||
|
//
|
||||||
|
// AWS Single Sign-On User Guide: https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html
|
||||||
|
package ssocreds
|
10
vendor/github.com/aws/aws-sdk-go/aws/credentials/ssocreds/os.go
generated
vendored
Normal file
10
vendor/github.com/aws/aws-sdk-go/aws/credentials/ssocreds/os.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package ssocreds
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
func getHomeDirectory() string {
|
||||||
|
return os.Getenv("HOME")
|
||||||
|
}
|
7
vendor/github.com/aws/aws-sdk-go/aws/credentials/ssocreds/os_windows.go
generated
vendored
Normal file
7
vendor/github.com/aws/aws-sdk-go/aws/credentials/ssocreds/os_windows.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package ssocreds
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
func getHomeDirectory() string {
|
||||||
|
return os.Getenv("USERPROFILE")
|
||||||
|
}
|
180
vendor/github.com/aws/aws-sdk-go/aws/credentials/ssocreds/provider.go
generated
vendored
Normal file
180
vendor/github.com/aws/aws-sdk-go/aws/credentials/ssocreds/provider.go
generated
vendored
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
package ssocreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/service/sso"
|
||||||
|
"github.com/aws/aws-sdk-go/service/sso/ssoiface"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrCodeSSOProviderInvalidToken is the code type that is returned if loaded token has expired or is otherwise invalid.
|
||||||
|
// To refresh the SSO session run aws sso login with the corresponding profile.
|
||||||
|
const ErrCodeSSOProviderInvalidToken = "SSOProviderInvalidToken"
|
||||||
|
|
||||||
|
const invalidTokenMessage = "the SSO session has expired or is invalid"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
nowTime = time.Now
|
||||||
|
defaultCacheLocation = defaultCacheLocationImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
var nowTime func() time.Time
|
||||||
|
|
||||||
|
// ProviderName is the name of the provider used to specify the source of credentials.
|
||||||
|
const ProviderName = "SSOProvider"
|
||||||
|
|
||||||
|
var defaultCacheLocation func() string
|
||||||
|
|
||||||
|
func defaultCacheLocationImpl() string {
|
||||||
|
return filepath.Join(getHomeDirectory(), ".aws", "sso", "cache")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider is an AWS credential provider that retrieves temporary AWS credentials by exchanging an SSO login token.
|
||||||
|
type Provider struct {
|
||||||
|
credentials.Expiry
|
||||||
|
|
||||||
|
// The Client which is configured for the AWS Region where the AWS SSO user portal is located.
|
||||||
|
Client ssoiface.SSOAPI
|
||||||
|
|
||||||
|
// The AWS account that is assigned to the user.
|
||||||
|
AccountID string
|
||||||
|
|
||||||
|
// The role name that is assigned to the user.
|
||||||
|
RoleName string
|
||||||
|
|
||||||
|
// The URL that points to the organization's AWS Single Sign-On (AWS SSO) user portal.
|
||||||
|
StartURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentials returns a new AWS Single Sign-On (AWS SSO) credential provider. The ConfigProvider is expected to be configured
|
||||||
|
// for the AWS Region where the AWS SSO user portal is located.
|
||||||
|
func NewCredentials(configProvider client.ConfigProvider, accountID, roleName, startURL string, optFns ...func(provider *Provider)) *credentials.Credentials {
|
||||||
|
return NewCredentialsWithClient(sso.New(configProvider), accountID, roleName, startURL, optFns...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentialsWithClient returns a new AWS Single Sign-On (AWS SSO) credential provider. The provided client is expected to be configured
|
||||||
|
// for the AWS Region where the AWS SSO user portal is located.
|
||||||
|
func NewCredentialsWithClient(client ssoiface.SSOAPI, accountID, roleName, startURL string, optFns ...func(provider *Provider)) *credentials.Credentials {
|
||||||
|
p := &Provider{
|
||||||
|
Client: client,
|
||||||
|
AccountID: accountID,
|
||||||
|
RoleName: roleName,
|
||||||
|
StartURL: startURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fn := range optFns {
|
||||||
|
fn(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials.NewCredentials(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve retrieves temporary AWS credentials from the configured Amazon Single Sign-On (AWS SSO) user portal
|
||||||
|
// by exchanging the accessToken present in ~/.aws/sso/cache.
|
||||||
|
func (p *Provider) Retrieve() (credentials.Value, error) {
|
||||||
|
return p.RetrieveWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveWithContext retrieves temporary AWS credentials from the configured Amazon Single Sign-On (AWS SSO) user portal
|
||||||
|
// by exchanging the accessToken present in ~/.aws/sso/cache.
|
||||||
|
func (p *Provider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
||||||
|
tokenFile, err := loadTokenFile(p.StartURL)
|
||||||
|
if err != nil {
|
||||||
|
return credentials.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := p.Client.GetRoleCredentialsWithContext(ctx, &sso.GetRoleCredentialsInput{
|
||||||
|
AccessToken: &tokenFile.AccessToken,
|
||||||
|
AccountId: &p.AccountID,
|
||||||
|
RoleName: &p.RoleName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return credentials.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
expireTime := time.Unix(0, aws.Int64Value(output.RoleCredentials.Expiration)*int64(time.Millisecond)).UTC()
|
||||||
|
p.SetExpiration(expireTime, 0)
|
||||||
|
|
||||||
|
return credentials.Value{
|
||||||
|
AccessKeyID: aws.StringValue(output.RoleCredentials.AccessKeyId),
|
||||||
|
SecretAccessKey: aws.StringValue(output.RoleCredentials.SecretAccessKey),
|
||||||
|
SessionToken: aws.StringValue(output.RoleCredentials.SessionToken),
|
||||||
|
ProviderName: ProviderName,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCacheFileName(url string) (string, error) {
|
||||||
|
hash := sha1.New()
|
||||||
|
_, err := hash.Write([]byte(url))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return strings.ToLower(hex.EncodeToString(hash.Sum(nil))) + ".json", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type rfc3339 time.Time
|
||||||
|
|
||||||
|
func (r *rfc3339) UnmarshalJSON(bytes []byte) error {
|
||||||
|
var value string
|
||||||
|
|
||||||
|
if err := json.Unmarshal(bytes, &value); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
parse, err := time.Parse(time.RFC3339, value)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("expected RFC3339 timestamp: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
*r = rfc3339(parse)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type token struct {
|
||||||
|
AccessToken string `json:"accessToken"`
|
||||||
|
ExpiresAt rfc3339 `json:"expiresAt"`
|
||||||
|
Region string `json:"region,omitempty"`
|
||||||
|
StartURL string `json:"startUrl,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t token) Expired() bool {
|
||||||
|
return nowTime().Round(0).After(time.Time(t.ExpiresAt))
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadTokenFile(startURL string) (t token, err error) {
|
||||||
|
key, err := getCacheFileName(startURL)
|
||||||
|
if err != nil {
|
||||||
|
return token{}, awserr.New(ErrCodeSSOProviderInvalidToken, invalidTokenMessage, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileBytes, err := ioutil.ReadFile(filepath.Join(defaultCacheLocation(), key))
|
||||||
|
if err != nil {
|
||||||
|
return token{}, awserr.New(ErrCodeSSOProviderInvalidToken, invalidTokenMessage, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(fileBytes, &t); err != nil {
|
||||||
|
return token{}, awserr.New(ErrCodeSSOProviderInvalidToken, invalidTokenMessage, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(t.AccessToken) == 0 {
|
||||||
|
return token{}, awserr.New(ErrCodeSSOProviderInvalidToken, invalidTokenMessage, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Expired() {
|
||||||
|
return token{}, awserr.New(ErrCodeSSOProviderInvalidToken, invalidTokenMessage, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
57
vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider.go
generated
vendored
Normal file
57
vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StaticProviderName provides a name of Static provider
|
||||||
|
const StaticProviderName = "StaticProvider"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrStaticCredentialsEmpty is emitted when static credentials are empty.
|
||||||
|
ErrStaticCredentialsEmpty = awserr.New("EmptyStaticCreds", "static credentials are empty", nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
// A StaticProvider is a set of credentials which are set programmatically,
|
||||||
|
// and will never expire.
|
||||||
|
type StaticProvider struct {
|
||||||
|
Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStaticCredentials returns a pointer to a new Credentials object
|
||||||
|
// wrapping a static credentials value provider. Token is only required
|
||||||
|
// for temporary security credentials retrieved via STS, otherwise an empty
|
||||||
|
// string can be passed for this parameter.
|
||||||
|
func NewStaticCredentials(id, secret, token string) *Credentials {
|
||||||
|
return NewCredentials(&StaticProvider{Value: Value{
|
||||||
|
AccessKeyID: id,
|
||||||
|
SecretAccessKey: secret,
|
||||||
|
SessionToken: token,
|
||||||
|
}})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStaticCredentialsFromCreds returns a pointer to a new Credentials object
|
||||||
|
// wrapping the static credentials value provide. Same as NewStaticCredentials
|
||||||
|
// but takes the creds Value instead of individual fields
|
||||||
|
func NewStaticCredentialsFromCreds(creds Value) *Credentials {
|
||||||
|
return NewCredentials(&StaticProvider{Value: creds})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve returns the credentials or error if the credentials are invalid.
|
||||||
|
func (s *StaticProvider) Retrieve() (Value, error) {
|
||||||
|
if s.AccessKeyID == "" || s.SecretAccessKey == "" {
|
||||||
|
return Value{ProviderName: StaticProviderName}, ErrStaticCredentialsEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.Value.ProviderName) == 0 {
|
||||||
|
s.Value.ProviderName = StaticProviderName
|
||||||
|
}
|
||||||
|
return s.Value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns if the credentials are expired.
|
||||||
|
//
|
||||||
|
// For StaticProvider, the credentials never expired.
|
||||||
|
func (s *StaticProvider) IsExpired() bool {
|
||||||
|
return false
|
||||||
|
}
|
367
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
Normal file
367
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
/*
|
||||||
|
Package stscreds are credential Providers to retrieve STS AWS credentials.
|
||||||
|
|
||||||
|
STS provides multiple ways to retrieve credentials which can be used when making
|
||||||
|
future AWS service API operation calls.
|
||||||
|
|
||||||
|
The SDK will ensure that per instance of credentials.Credentials all requests
|
||||||
|
to refresh the credentials will be synchronized. But, the SDK is unable to
|
||||||
|
ensure synchronous usage of the AssumeRoleProvider if the value is shared
|
||||||
|
between multiple Credentials, Sessions or service clients.
|
||||||
|
|
||||||
|
Assume Role
|
||||||
|
|
||||||
|
To assume an IAM role using STS with the SDK you can create a new Credentials
|
||||||
|
with the SDKs's stscreds package.
|
||||||
|
|
||||||
|
// 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})
|
||||||
|
|
||||||
|
Assume Role with static MFA Token
|
||||||
|
|
||||||
|
To assume an IAM role with a MFA token you can either specify a MFA token code
|
||||||
|
directly or provide a function to prompt the user each time the credentials
|
||||||
|
need to refresh the role's credentials. Specifying the TokenCode should be used
|
||||||
|
for short lived operations that will not need to be refreshed, and when you do
|
||||||
|
not want to have direct control over the user provides their MFA token.
|
||||||
|
|
||||||
|
With TokenCode the AssumeRoleProvider will be not be able to refresh the role's
|
||||||
|
credentials.
|
||||||
|
|
||||||
|
// Create the credentials from AssumeRoleProvider to assume the role
|
||||||
|
// referenced by the "myRoleARN" ARN using the MFA token code provided.
|
||||||
|
creds := stscreds.NewCredentials(sess, "myRoleArn", func(p *stscreds.AssumeRoleProvider) {
|
||||||
|
p.SerialNumber = aws.String("myTokenSerialNumber")
|
||||||
|
p.TokenCode = aws.String("00000000")
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create service client value configured for credentials
|
||||||
|
// from assumed role.
|
||||||
|
svc := s3.New(sess, &aws.Config{Credentials: creds})
|
||||||
|
|
||||||
|
Assume Role with MFA Token Provider
|
||||||
|
|
||||||
|
To assume an IAM role with MFA for longer running tasks where the credentials
|
||||||
|
may need to be refreshed setting the TokenProvider field of AssumeRoleProvider
|
||||||
|
will allow the credential provider to prompt for new MFA token code when the
|
||||||
|
role's credentials need to be refreshed.
|
||||||
|
|
||||||
|
The StdinTokenProvider function is available to prompt on stdin to retrieve
|
||||||
|
the MFA token code from the user. You can also implement custom prompts by
|
||||||
|
satisfing the TokenProvider function signature.
|
||||||
|
|
||||||
|
Using StdinTokenProvider with multiple AssumeRoleProviders, or Credentials will
|
||||||
|
have undesirable results as the StdinTokenProvider will not be synchronized. A
|
||||||
|
single Credentials with an AssumeRoleProvider can be shared safely.
|
||||||
|
|
||||||
|
// Create the credentials from AssumeRoleProvider to assume the role
|
||||||
|
// referenced by the "myRoleARN" ARN. Prompting for MFA token from stdin.
|
||||||
|
creds := stscreds.NewCredentials(sess, "myRoleArn", func(p *stscreds.AssumeRoleProvider) {
|
||||||
|
p.SerialNumber = aws.String("myTokenSerialNumber")
|
||||||
|
p.TokenProvider = stscreds.StdinTokenProvider
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create service client value configured for credentials
|
||||||
|
// from assumed role.
|
||||||
|
svc := s3.New(sess, &aws.Config{Credentials: creds})
|
||||||
|
|
||||||
|
*/
|
||||||
|
package stscreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/client"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/sdkrand"
|
||||||
|
"github.com/aws/aws-sdk-go/service/sts"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StdinTokenProvider will prompt on stderr and read from stdin for a string value.
|
||||||
|
// An error is returned if reading from stdin fails.
|
||||||
|
//
|
||||||
|
// Use this function to read MFA tokens from stdin. The function makes no attempt
|
||||||
|
// to make atomic prompts from stdin across multiple gorouties.
|
||||||
|
//
|
||||||
|
// Using StdinTokenProvider with multiple AssumeRoleProviders, or Credentials will
|
||||||
|
// have undesirable results as the StdinTokenProvider will not be synchronized. A
|
||||||
|
// single Credentials with an AssumeRoleProvider can be shared safely
|
||||||
|
//
|
||||||
|
// Will wait forever until something is provided on the stdin.
|
||||||
|
func StdinTokenProvider() (string, error) {
|
||||||
|
var v string
|
||||||
|
fmt.Fprintf(os.Stderr, "Assume Role MFA token code: ")
|
||||||
|
_, err := fmt.Scanln(&v)
|
||||||
|
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProviderName provides a name of AssumeRole provider
|
||||||
|
const ProviderName = "AssumeRoleProvider"
|
||||||
|
|
||||||
|
// AssumeRoler represents the minimal subset of the STS client API used by this provider.
|
||||||
|
type AssumeRoler interface {
|
||||||
|
AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type assumeRolerWithContext interface {
|
||||||
|
AssumeRoleWithContext(aws.Context, *sts.AssumeRoleInput, ...request.Option) (*sts.AssumeRoleOutput, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultDuration is the default amount of time in minutes that the credentials
|
||||||
|
// will be valid for.
|
||||||
|
var DefaultDuration = time.Duration(15) * time.Minute
|
||||||
|
|
||||||
|
// AssumeRoleProvider retrieves temporary credentials from the STS service, and
|
||||||
|
// keeps track of their expiration time.
|
||||||
|
//
|
||||||
|
// This credential provider will be used by the SDKs default credential change
|
||||||
|
// when shared configuration is enabled, and the shared config or shared credentials
|
||||||
|
// file configure assume role. See Session docs for how to do this.
|
||||||
|
//
|
||||||
|
// AssumeRoleProvider does not provide any synchronization and it is not safe
|
||||||
|
// to share this value across multiple Credentials, Sessions, or service clients
|
||||||
|
// without also sharing the same Credentials instance.
|
||||||
|
type AssumeRoleProvider struct {
|
||||||
|
credentials.Expiry
|
||||||
|
|
||||||
|
// STS client to make assume role request with.
|
||||||
|
Client AssumeRoler
|
||||||
|
|
||||||
|
// Role to be assumed.
|
||||||
|
RoleARN string
|
||||||
|
|
||||||
|
// Session name, if you wish to reuse the credentials elsewhere.
|
||||||
|
RoleSessionName string
|
||||||
|
|
||||||
|
// Optional, you can pass tag key-value pairs to your session. These tags are called session tags.
|
||||||
|
Tags []*sts.Tag
|
||||||
|
|
||||||
|
// A list of keys for session tags that you want to set as transitive.
|
||||||
|
// If you set a tag key as transitive, the corresponding key and value passes to subsequent sessions in a role chain.
|
||||||
|
TransitiveTagKeys []*string
|
||||||
|
|
||||||
|
// Expiry duration of the STS credentials. Defaults to 15 minutes if not set.
|
||||||
|
Duration time.Duration
|
||||||
|
|
||||||
|
// Optional ExternalID to pass along, defaults to nil if not set.
|
||||||
|
ExternalID *string
|
||||||
|
|
||||||
|
// The policy plain text must be 2048 bytes or shorter. However, an internal
|
||||||
|
// conversion compresses it into a packed binary format with a separate limit.
|
||||||
|
// The PackedPolicySize response element indicates by percentage how close to
|
||||||
|
// the upper size limit the policy is, with 100% equaling the maximum allowed
|
||||||
|
// size.
|
||||||
|
Policy *string
|
||||||
|
|
||||||
|
// The ARNs of IAM managed policies you want to use as managed session policies.
|
||||||
|
// The policies must exist in the same account as the role.
|
||||||
|
//
|
||||||
|
// This parameter is optional. You can provide up to 10 managed policy ARNs.
|
||||||
|
// However, the plain text that you use for both inline and managed session
|
||||||
|
// policies can't exceed 2,048 characters.
|
||||||
|
//
|
||||||
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
|
// and tags for your request are to the upper size limit.
|
||||||
|
//
|
||||||
|
// Passing policies to this operation returns new temporary credentials. The
|
||||||
|
// resulting session's permissions are the intersection of the role's identity-based
|
||||||
|
// policy and the session policies. You can use the role's temporary credentials
|
||||||
|
// in subsequent AWS API calls to access resources in the account that owns
|
||||||
|
// the role. You cannot use session policies to grant more permissions than
|
||||||
|
// those allowed by the identity-based policy of the role that is being assumed.
|
||||||
|
// For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
PolicyArns []*sts.PolicyDescriptorType
|
||||||
|
|
||||||
|
// The identification number of the MFA device that is associated with the user
|
||||||
|
// who is making the AssumeRole call. Specify this value if the trust policy
|
||||||
|
// of the role being assumed includes a condition that requires MFA authentication.
|
||||||
|
// The value is either the serial number for a hardware device (such as GAHT12345678)
|
||||||
|
// or an Amazon Resource Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user).
|
||||||
|
SerialNumber *string
|
||||||
|
|
||||||
|
// The value provided by the MFA device, if the trust policy of the role being
|
||||||
|
// assumed requires MFA (that is, if the policy includes a condition that tests
|
||||||
|
// for MFA). If the role being assumed requires MFA and if the TokenCode value
|
||||||
|
// is missing or expired, the AssumeRole call returns an "access denied" error.
|
||||||
|
//
|
||||||
|
// If SerialNumber is set and neither TokenCode nor TokenProvider are also
|
||||||
|
// set an error will be returned.
|
||||||
|
TokenCode *string
|
||||||
|
|
||||||
|
// Async method of providing MFA token code for assuming an IAM role with MFA.
|
||||||
|
// The value returned by the function will be used as the TokenCode in the Retrieve
|
||||||
|
// call. See StdinTokenProvider for a provider that prompts and reads from stdin.
|
||||||
|
//
|
||||||
|
// This token provider will be called when ever the assumed role's
|
||||||
|
// credentials need to be refreshed when SerialNumber is also set and
|
||||||
|
// TokenCode is not set.
|
||||||
|
//
|
||||||
|
// If both TokenCode and TokenProvider is set, TokenProvider will be used and
|
||||||
|
// TokenCode is ignored.
|
||||||
|
TokenProvider func() (string, error)
|
||||||
|
|
||||||
|
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||||
|
// the credentials actually expiring. This is beneficial so race conditions
|
||||||
|
// with expiring credentials do not cause request to fail unexpectedly
|
||||||
|
// due to ExpiredTokenException exceptions.
|
||||||
|
//
|
||||||
|
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
|
||||||
|
// 10 seconds before the credentials are actually expired.
|
||||||
|
//
|
||||||
|
// If ExpiryWindow is 0 or less it will be ignored.
|
||||||
|
ExpiryWindow time.Duration
|
||||||
|
|
||||||
|
// MaxJitterFrac reduces the effective Duration of each credential requested
|
||||||
|
// by a random percentage between 0 and MaxJitterFraction. MaxJitterFrac must
|
||||||
|
// have a value between 0 and 1. Any other value may lead to expected behavior.
|
||||||
|
// With a MaxJitterFrac value of 0, default) will no jitter will be used.
|
||||||
|
//
|
||||||
|
// For example, with a Duration of 30m and a MaxJitterFrac of 0.1, the
|
||||||
|
// AssumeRole call will be made with an arbitrary Duration between 27m and
|
||||||
|
// 30m.
|
||||||
|
//
|
||||||
|
// MaxJitterFrac should not be negative.
|
||||||
|
MaxJitterFrac float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentials returns a pointer to a new Credentials value wrapping the
|
||||||
|
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||||
|
// role will be named after a nanosecond timestamp of this operation. The
|
||||||
|
// Credentials value will attempt to refresh the credentials using the provider
|
||||||
|
// when Credentials.Get is called, if the cached credentials are expiring.
|
||||||
|
//
|
||||||
|
// Takes a Config provider to create the STS client. The ConfigProvider is
|
||||||
|
// satisfied by the session.Session type.
|
||||||
|
//
|
||||||
|
// It is safe to share the returned Credentials with multiple Sessions and
|
||||||
|
// service clients. All access to the credentials and refreshing them
|
||||||
|
// will be synchronized.
|
||||||
|
func NewCredentials(c client.ConfigProvider, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||||
|
p := &AssumeRoleProvider{
|
||||||
|
Client: sts.New(c),
|
||||||
|
RoleARN: roleARN,
|
||||||
|
Duration: DefaultDuration,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials.NewCredentials(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentialsWithClient returns a pointer to a new Credentials value wrapping the
|
||||||
|
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||||
|
// role will be named after a nanosecond timestamp of this operation. The
|
||||||
|
// Credentials value will attempt to refresh the credentials using the provider
|
||||||
|
// when Credentials.Get is called, if the cached credentials are expiring.
|
||||||
|
//
|
||||||
|
// Takes an AssumeRoler which can be satisfied by the STS client.
|
||||||
|
//
|
||||||
|
// It is safe to share the returned Credentials with multiple Sessions and
|
||||||
|
// service clients. All access to the credentials and refreshing them
|
||||||
|
// will be synchronized.
|
||||||
|
func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||||
|
p := &AssumeRoleProvider{
|
||||||
|
Client: svc,
|
||||||
|
RoleARN: roleARN,
|
||||||
|
Duration: DefaultDuration,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials.NewCredentials(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve generates a new set of temporary credentials using STS.
|
||||||
|
func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
|
return p.RetrieveWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveWithContext generates a new set of temporary credentials using STS.
|
||||||
|
func (p *AssumeRoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
||||||
|
// Apply defaults where parameters are not set.
|
||||||
|
if p.RoleSessionName == "" {
|
||||||
|
// Try to work out a role name that will hopefully end up unique.
|
||||||
|
p.RoleSessionName = fmt.Sprintf("%d", time.Now().UTC().UnixNano())
|
||||||
|
}
|
||||||
|
if p.Duration == 0 {
|
||||||
|
// Expire as often as AWS permits.
|
||||||
|
p.Duration = DefaultDuration
|
||||||
|
}
|
||||||
|
jitter := time.Duration(sdkrand.SeededRand.Float64() * p.MaxJitterFrac * float64(p.Duration))
|
||||||
|
input := &sts.AssumeRoleInput{
|
||||||
|
DurationSeconds: aws.Int64(int64((p.Duration - jitter) / time.Second)),
|
||||||
|
RoleArn: aws.String(p.RoleARN),
|
||||||
|
RoleSessionName: aws.String(p.RoleSessionName),
|
||||||
|
ExternalId: p.ExternalID,
|
||||||
|
Tags: p.Tags,
|
||||||
|
PolicyArns: p.PolicyArns,
|
||||||
|
TransitiveTagKeys: p.TransitiveTagKeys,
|
||||||
|
}
|
||||||
|
if p.Policy != nil {
|
||||||
|
input.Policy = p.Policy
|
||||||
|
}
|
||||||
|
if p.SerialNumber != nil {
|
||||||
|
if p.TokenCode != nil {
|
||||||
|
input.SerialNumber = p.SerialNumber
|
||||||
|
input.TokenCode = p.TokenCode
|
||||||
|
} else if p.TokenProvider != nil {
|
||||||
|
input.SerialNumber = p.SerialNumber
|
||||||
|
code, err := p.TokenProvider()
|
||||||
|
if err != nil {
|
||||||
|
return credentials.Value{ProviderName: ProviderName}, err
|
||||||
|
}
|
||||||
|
input.TokenCode = aws.String(code)
|
||||||
|
} else {
|
||||||
|
return credentials.Value{ProviderName: ProviderName},
|
||||||
|
awserr.New("AssumeRoleTokenNotAvailable",
|
||||||
|
"assume role with MFA enabled, but neither TokenCode nor TokenProvider are set", nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var roleOutput *sts.AssumeRoleOutput
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if c, ok := p.Client.(assumeRolerWithContext); ok {
|
||||||
|
roleOutput, err = c.AssumeRoleWithContext(ctx, input)
|
||||||
|
} else {
|
||||||
|
roleOutput, err = p.Client.AssumeRole(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return credentials.Value{ProviderName: ProviderName}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will proactively generate new credentials before they expire.
|
||||||
|
p.SetExpiration(*roleOutput.Credentials.Expiration, p.ExpiryWindow)
|
||||||
|
|
||||||
|
return credentials.Value{
|
||||||
|
AccessKeyID: *roleOutput.Credentials.AccessKeyId,
|
||||||
|
SecretAccessKey: *roleOutput.Credentials.SecretAccessKey,
|
||||||
|
SessionToken: *roleOutput.Credentials.SessionToken,
|
||||||
|
ProviderName: ProviderName,
|
||||||
|
}, nil
|
||||||
|
}
|
182
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/web_identity_provider.go
generated
vendored
Normal file
182
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/web_identity_provider.go
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
package stscreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/service/sts"
|
||||||
|
"github.com/aws/aws-sdk-go/service/sts/stsiface"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ErrCodeWebIdentity will be used as an error code when constructing
|
||||||
|
// a new error to be returned during session creation or retrieval.
|
||||||
|
ErrCodeWebIdentity = "WebIdentityErr"
|
||||||
|
|
||||||
|
// WebIdentityProviderName is the web identity provider name
|
||||||
|
WebIdentityProviderName = "WebIdentityCredentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
// now is used to return a time.Time object representing
|
||||||
|
// the current time. This can be used to easily test and
|
||||||
|
// compare test values.
|
||||||
|
var now = time.Now
|
||||||
|
|
||||||
|
// TokenFetcher should return WebIdentity token bytes or an error
|
||||||
|
type TokenFetcher interface {
|
||||||
|
FetchToken(credentials.Context) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchTokenPath is a path to a WebIdentity token file
|
||||||
|
type FetchTokenPath string
|
||||||
|
|
||||||
|
// FetchToken returns a token by reading from the filesystem
|
||||||
|
func (f FetchTokenPath) FetchToken(ctx credentials.Context) ([]byte, error) {
|
||||||
|
data, err := ioutil.ReadFile(string(f))
|
||||||
|
if err != nil {
|
||||||
|
errMsg := fmt.Sprintf("unable to read file at %s", f)
|
||||||
|
return nil, awserr.New(ErrCodeWebIdentity, errMsg, err)
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebIdentityRoleProvider is used to retrieve credentials using
|
||||||
|
// an OIDC token.
|
||||||
|
type WebIdentityRoleProvider struct {
|
||||||
|
credentials.Expiry
|
||||||
|
|
||||||
|
// The policy ARNs to use with the web identity assumed role.
|
||||||
|
PolicyArns []*sts.PolicyDescriptorType
|
||||||
|
|
||||||
|
// Duration the STS credentials will be valid for. Truncated to seconds.
|
||||||
|
// If unset, the assumed role will use AssumeRoleWithWebIdentity's default
|
||||||
|
// expiry duration. See
|
||||||
|
// https://docs.aws.amazon.com/sdk-for-go/api/service/sts/#STS.AssumeRoleWithWebIdentity
|
||||||
|
// for more information.
|
||||||
|
Duration time.Duration
|
||||||
|
|
||||||
|
// The amount of time the credentials will be refreshed before they expire.
|
||||||
|
// This is useful refresh credentials before they expire to reduce risk of
|
||||||
|
// using credentials as they expire. If unset, will default to no expiry
|
||||||
|
// window.
|
||||||
|
ExpiryWindow time.Duration
|
||||||
|
|
||||||
|
client stsiface.STSAPI
|
||||||
|
|
||||||
|
tokenFetcher TokenFetcher
|
||||||
|
roleARN string
|
||||||
|
roleSessionName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWebIdentityCredentials will return a new set of credentials with a given
|
||||||
|
// configuration, role arn, and token file path.
|
||||||
|
//
|
||||||
|
// Deprecated: Use NewWebIdentityRoleProviderWithOptions for flexible
|
||||||
|
// functional options, and wrap with credentials.NewCredentials helper.
|
||||||
|
func NewWebIdentityCredentials(c client.ConfigProvider, roleARN, roleSessionName, path string) *credentials.Credentials {
|
||||||
|
svc := sts.New(c)
|
||||||
|
p := NewWebIdentityRoleProvider(svc, roleARN, roleSessionName, path)
|
||||||
|
return credentials.NewCredentials(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWebIdentityRoleProvider will return a new WebIdentityRoleProvider with the
|
||||||
|
// provided stsiface.STSAPI
|
||||||
|
//
|
||||||
|
// Deprecated: Use NewWebIdentityRoleProviderWithOptions for flexible
|
||||||
|
// functional options.
|
||||||
|
func NewWebIdentityRoleProvider(svc stsiface.STSAPI, roleARN, roleSessionName, path string) *WebIdentityRoleProvider {
|
||||||
|
return NewWebIdentityRoleProviderWithOptions(svc, roleARN, roleSessionName, FetchTokenPath(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWebIdentityRoleProviderWithToken will return a new WebIdentityRoleProvider with the
|
||||||
|
// provided stsiface.STSAPI and a TokenFetcher
|
||||||
|
//
|
||||||
|
// Deprecated: Use NewWebIdentityRoleProviderWithOptions for flexible
|
||||||
|
// functional options.
|
||||||
|
func NewWebIdentityRoleProviderWithToken(svc stsiface.STSAPI, roleARN, roleSessionName string, tokenFetcher TokenFetcher) *WebIdentityRoleProvider {
|
||||||
|
return NewWebIdentityRoleProviderWithOptions(svc, roleARN, roleSessionName, tokenFetcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWebIdentityRoleProviderWithOptions will return an initialize
|
||||||
|
// WebIdentityRoleProvider with the provided stsiface.STSAPI, role ARN, and a
|
||||||
|
// TokenFetcher. Additional options can be provided as functional options.
|
||||||
|
//
|
||||||
|
// TokenFetcher is the implementation that will retrieve the JWT token from to
|
||||||
|
// assume the role with. Use the provided FetchTokenPath implementation to
|
||||||
|
// retrieve the JWT token using a file system path.
|
||||||
|
func NewWebIdentityRoleProviderWithOptions(svc stsiface.STSAPI, roleARN, roleSessionName string, tokenFetcher TokenFetcher, optFns ...func(*WebIdentityRoleProvider)) *WebIdentityRoleProvider {
|
||||||
|
p := WebIdentityRoleProvider{
|
||||||
|
client: svc,
|
||||||
|
tokenFetcher: tokenFetcher,
|
||||||
|
roleARN: roleARN,
|
||||||
|
roleSessionName: roleSessionName,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fn := range optFns {
|
||||||
|
fn(&p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve will attempt to assume a role from a token which is located at
|
||||||
|
// 'WebIdentityTokenFilePath' specified destination and if that is empty an
|
||||||
|
// error will be returned.
|
||||||
|
func (p *WebIdentityRoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
|
return p.RetrieveWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveWithContext will attempt to assume a role from a token which is
|
||||||
|
// located at 'WebIdentityTokenFilePath' specified destination and if that is
|
||||||
|
// empty an error will be returned.
|
||||||
|
func (p *WebIdentityRoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
||||||
|
b, err := p.tokenFetcher.FetchToken(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return credentials.Value{}, awserr.New(ErrCodeWebIdentity, "failed fetching WebIdentity token: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionName := p.roleSessionName
|
||||||
|
if len(sessionName) == 0 {
|
||||||
|
// session name is used to uniquely identify a session. This simply
|
||||||
|
// uses unix time in nanoseconds to uniquely identify sessions.
|
||||||
|
sessionName = strconv.FormatInt(now().UnixNano(), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
var duration *int64
|
||||||
|
if p.Duration != 0 {
|
||||||
|
duration = aws.Int64(int64(p.Duration / time.Second))
|
||||||
|
}
|
||||||
|
|
||||||
|
req, resp := p.client.AssumeRoleWithWebIdentityRequest(&sts.AssumeRoleWithWebIdentityInput{
|
||||||
|
PolicyArns: p.PolicyArns,
|
||||||
|
RoleArn: &p.roleARN,
|
||||||
|
RoleSessionName: &sessionName,
|
||||||
|
WebIdentityToken: aws.String(string(b)),
|
||||||
|
DurationSeconds: duration,
|
||||||
|
})
|
||||||
|
|
||||||
|
req.SetContext(ctx)
|
||||||
|
|
||||||
|
// InvalidIdentityToken error is a temporary error that can occur
|
||||||
|
// when assuming an Role with a JWT web identity token.
|
||||||
|
req.RetryErrorCodes = append(req.RetryErrorCodes, sts.ErrCodeInvalidIdentityTokenException)
|
||||||
|
if err := req.Send(); err != nil {
|
||||||
|
return credentials.Value{}, awserr.New(ErrCodeWebIdentity, "failed to retrieve credentials", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetExpiration(aws.TimeValue(resp.Credentials.Expiration), p.ExpiryWindow)
|
||||||
|
|
||||||
|
value := credentials.Value{
|
||||||
|
AccessKeyID: aws.StringValue(resp.Credentials.AccessKeyId),
|
||||||
|
SecretAccessKey: aws.StringValue(resp.Credentials.SecretAccessKey),
|
||||||
|
SessionToken: aws.StringValue(resp.Credentials.SessionToken),
|
||||||
|
ProviderName: WebIdentityProviderName,
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
}
|
69
vendor/github.com/aws/aws-sdk-go/aws/csm/doc.go
generated
vendored
Normal file
69
vendor/github.com/aws/aws-sdk-go/aws/csm/doc.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Package csm provides the Client Side Monitoring (CSM) client which enables
|
||||||
|
// sending metrics via UDP connection to the CSM agent. This package provides
|
||||||
|
// control options, and configuration for the CSM client. The client can be
|
||||||
|
// controlled manually, or automatically via the SDK's Session configuration.
|
||||||
|
//
|
||||||
|
// Enabling CSM client via SDK's Session configuration
|
||||||
|
//
|
||||||
|
// The CSM client can be enabled automatically via SDK's Session configuration.
|
||||||
|
// The SDK's session configuration enables the CSM client if the AWS_CSM_PORT
|
||||||
|
// environment variable is set to a non-empty value.
|
||||||
|
//
|
||||||
|
// The configuration options for the CSM client via the SDK's session
|
||||||
|
// configuration are:
|
||||||
|
//
|
||||||
|
// * AWS_CSM_PORT=<port number>
|
||||||
|
// The port number the CSM agent will receive metrics on.
|
||||||
|
//
|
||||||
|
// * AWS_CSM_HOST=<hostname or ip>
|
||||||
|
// The hostname, or IP address the CSM agent will receive metrics on.
|
||||||
|
// Without port number.
|
||||||
|
//
|
||||||
|
// Manually enabling the CSM client
|
||||||
|
//
|
||||||
|
// The CSM client can be started, paused, and resumed manually. The Start
|
||||||
|
// function will enable the CSM client to publish metrics to the CSM agent. It
|
||||||
|
// is safe to call Start concurrently, but if Start is called additional times
|
||||||
|
// with different ClientID or address it will panic.
|
||||||
|
//
|
||||||
|
// r, err := csm.Start("clientID", ":31000")
|
||||||
|
// if err != nil {
|
||||||
|
// panic(fmt.Errorf("failed starting CSM: %v", err))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// When controlling the CSM client manually, you must also inject its request
|
||||||
|
// handlers into the SDK's Session configuration for the SDK's API clients to
|
||||||
|
// publish metrics.
|
||||||
|
//
|
||||||
|
// sess, err := session.NewSession(&aws.Config{})
|
||||||
|
// if err != nil {
|
||||||
|
// panic(fmt.Errorf("failed loading session: %v", err))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Add CSM client's metric publishing request handlers to the SDK's
|
||||||
|
// // Session Configuration.
|
||||||
|
// r.InjectHandlers(&sess.Handlers)
|
||||||
|
//
|
||||||
|
// Controlling CSM client
|
||||||
|
//
|
||||||
|
// Once the CSM client has been enabled the Get function will return a Reporter
|
||||||
|
// value that you can use to pause and resume the metrics published to the CSM
|
||||||
|
// agent. If Get function is called before the reporter is enabled with the
|
||||||
|
// Start function or via SDK's Session configuration nil will be returned.
|
||||||
|
//
|
||||||
|
// The Pause method can be called to stop the CSM client publishing metrics to
|
||||||
|
// the CSM agent. The Continue method will resume metric publishing.
|
||||||
|
//
|
||||||
|
// // Get the CSM client Reporter.
|
||||||
|
// r := csm.Get()
|
||||||
|
//
|
||||||
|
// // Will pause monitoring
|
||||||
|
// r.Pause()
|
||||||
|
// resp, err = client.GetObject(&s3.GetObjectInput{
|
||||||
|
// Bucket: aws.String("bucket"),
|
||||||
|
// Key: aws.String("key"),
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// // Resume monitoring
|
||||||
|
// r.Continue()
|
||||||
|
package csm
|
89
vendor/github.com/aws/aws-sdk-go/aws/csm/enable.go
generated
vendored
Normal file
89
vendor/github.com/aws/aws-sdk-go/aws/csm/enable.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package csm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
lock sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultPort is used when no port is specified.
|
||||||
|
DefaultPort = "31000"
|
||||||
|
|
||||||
|
// DefaultHost is the host that will be used when none is specified.
|
||||||
|
DefaultHost = "127.0.0.1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddressWithDefaults returns a CSM address built from the host and port
|
||||||
|
// values. If the host or port is not set, default values will be used
|
||||||
|
// instead. If host is "localhost" it will be replaced with "127.0.0.1".
|
||||||
|
func AddressWithDefaults(host, port string) string {
|
||||||
|
if len(host) == 0 || strings.EqualFold(host, "localhost") {
|
||||||
|
host = DefaultHost
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(port) == 0 {
|
||||||
|
port = DefaultPort
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only IP6 host can contain a colon
|
||||||
|
if strings.Contains(host, ":") {
|
||||||
|
return "[" + host + "]:" + port
|
||||||
|
}
|
||||||
|
|
||||||
|
return host + ":" + port
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start will start a long running go routine to capture
|
||||||
|
// client side metrics. Calling start multiple time will only
|
||||||
|
// start the metric listener once and will panic if a different
|
||||||
|
// client ID or port is passed in.
|
||||||
|
//
|
||||||
|
// r, err := csm.Start("clientID", "127.0.0.1:31000")
|
||||||
|
// if err != nil {
|
||||||
|
// panic(fmt.Errorf("expected no error, but received %v", err))
|
||||||
|
// }
|
||||||
|
// sess := session.NewSession()
|
||||||
|
// r.InjectHandlers(sess.Handlers)
|
||||||
|
//
|
||||||
|
// svc := s3.New(sess)
|
||||||
|
// out, err := svc.GetObject(&s3.GetObjectInput{
|
||||||
|
// Bucket: aws.String("bucket"),
|
||||||
|
// Key: aws.String("key"),
|
||||||
|
// })
|
||||||
|
func Start(clientID string, url string) (*Reporter, error) {
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
|
||||||
|
if sender == nil {
|
||||||
|
sender = newReporter(clientID, url)
|
||||||
|
} else {
|
||||||
|
if sender.clientID != clientID {
|
||||||
|
panic(fmt.Errorf("inconsistent client IDs. %q was expected, but received %q", sender.clientID, clientID))
|
||||||
|
}
|
||||||
|
|
||||||
|
if sender.url != url {
|
||||||
|
panic(fmt.Errorf("inconsistent URLs. %q was expected, but received %q", sender.url, url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := connect(url); err != nil {
|
||||||
|
sender = nil
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sender, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get will return a reporter if one exists, if one does not exist, nil will
|
||||||
|
// be returned.
|
||||||
|
func Get() *Reporter {
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
|
||||||
|
return sender
|
||||||
|
}
|
109
vendor/github.com/aws/aws-sdk-go/aws/csm/metric.go
generated
vendored
Normal file
109
vendor/github.com/aws/aws-sdk-go/aws/csm/metric.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package csm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
)
|
||||||
|
|
||||||
|
type metricTime time.Time
|
||||||
|
|
||||||
|
func (t metricTime) MarshalJSON() ([]byte, error) {
|
||||||
|
ns := time.Duration(time.Time(t).UnixNano())
|
||||||
|
return []byte(strconv.FormatInt(int64(ns/time.Millisecond), 10)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type metric struct {
|
||||||
|
ClientID *string `json:"ClientId,omitempty"`
|
||||||
|
API *string `json:"Api,omitempty"`
|
||||||
|
Service *string `json:"Service,omitempty"`
|
||||||
|
Timestamp *metricTime `json:"Timestamp,omitempty"`
|
||||||
|
Type *string `json:"Type,omitempty"`
|
||||||
|
Version *int `json:"Version,omitempty"`
|
||||||
|
|
||||||
|
AttemptCount *int `json:"AttemptCount,omitempty"`
|
||||||
|
Latency *int `json:"Latency,omitempty"`
|
||||||
|
|
||||||
|
Fqdn *string `json:"Fqdn,omitempty"`
|
||||||
|
UserAgent *string `json:"UserAgent,omitempty"`
|
||||||
|
AttemptLatency *int `json:"AttemptLatency,omitempty"`
|
||||||
|
|
||||||
|
SessionToken *string `json:"SessionToken,omitempty"`
|
||||||
|
Region *string `json:"Region,omitempty"`
|
||||||
|
AccessKey *string `json:"AccessKey,omitempty"`
|
||||||
|
HTTPStatusCode *int `json:"HttpStatusCode,omitempty"`
|
||||||
|
XAmzID2 *string `json:"XAmzId2,omitempty"`
|
||||||
|
XAmzRequestID *string `json:"XAmznRequestId,omitempty"`
|
||||||
|
|
||||||
|
AWSException *string `json:"AwsException,omitempty"`
|
||||||
|
AWSExceptionMessage *string `json:"AwsExceptionMessage,omitempty"`
|
||||||
|
SDKException *string `json:"SdkException,omitempty"`
|
||||||
|
SDKExceptionMessage *string `json:"SdkExceptionMessage,omitempty"`
|
||||||
|
|
||||||
|
FinalHTTPStatusCode *int `json:"FinalHttpStatusCode,omitempty"`
|
||||||
|
FinalAWSException *string `json:"FinalAwsException,omitempty"`
|
||||||
|
FinalAWSExceptionMessage *string `json:"FinalAwsExceptionMessage,omitempty"`
|
||||||
|
FinalSDKException *string `json:"FinalSdkException,omitempty"`
|
||||||
|
FinalSDKExceptionMessage *string `json:"FinalSdkExceptionMessage,omitempty"`
|
||||||
|
|
||||||
|
DestinationIP *string `json:"DestinationIp,omitempty"`
|
||||||
|
ConnectionReused *int `json:"ConnectionReused,omitempty"`
|
||||||
|
|
||||||
|
AcquireConnectionLatency *int `json:"AcquireConnectionLatency,omitempty"`
|
||||||
|
ConnectLatency *int `json:"ConnectLatency,omitempty"`
|
||||||
|
RequestLatency *int `json:"RequestLatency,omitempty"`
|
||||||
|
DNSLatency *int `json:"DnsLatency,omitempty"`
|
||||||
|
TCPLatency *int `json:"TcpLatency,omitempty"`
|
||||||
|
SSLLatency *int `json:"SslLatency,omitempty"`
|
||||||
|
|
||||||
|
MaxRetriesExceeded *int `json:"MaxRetriesExceeded,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metric) TruncateFields() {
|
||||||
|
m.ClientID = truncateString(m.ClientID, 255)
|
||||||
|
m.UserAgent = truncateString(m.UserAgent, 256)
|
||||||
|
|
||||||
|
m.AWSException = truncateString(m.AWSException, 128)
|
||||||
|
m.AWSExceptionMessage = truncateString(m.AWSExceptionMessage, 512)
|
||||||
|
|
||||||
|
m.SDKException = truncateString(m.SDKException, 128)
|
||||||
|
m.SDKExceptionMessage = truncateString(m.SDKExceptionMessage, 512)
|
||||||
|
|
||||||
|
m.FinalAWSException = truncateString(m.FinalAWSException, 128)
|
||||||
|
m.FinalAWSExceptionMessage = truncateString(m.FinalAWSExceptionMessage, 512)
|
||||||
|
|
||||||
|
m.FinalSDKException = truncateString(m.FinalSDKException, 128)
|
||||||
|
m.FinalSDKExceptionMessage = truncateString(m.FinalSDKExceptionMessage, 512)
|
||||||
|
}
|
||||||
|
|
||||||
|
func truncateString(v *string, l int) *string {
|
||||||
|
if v != nil && len(*v) > l {
|
||||||
|
nv := (*v)[:l]
|
||||||
|
return &nv
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metric) SetException(e metricException) {
|
||||||
|
switch te := e.(type) {
|
||||||
|
case awsException:
|
||||||
|
m.AWSException = aws.String(te.exception)
|
||||||
|
m.AWSExceptionMessage = aws.String(te.message)
|
||||||
|
case sdkException:
|
||||||
|
m.SDKException = aws.String(te.exception)
|
||||||
|
m.SDKExceptionMessage = aws.String(te.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metric) SetFinalException(e metricException) {
|
||||||
|
switch te := e.(type) {
|
||||||
|
case awsException:
|
||||||
|
m.FinalAWSException = aws.String(te.exception)
|
||||||
|
m.FinalAWSExceptionMessage = aws.String(te.message)
|
||||||
|
case sdkException:
|
||||||
|
m.FinalSDKException = aws.String(te.exception)
|
||||||
|
m.FinalSDKExceptionMessage = aws.String(te.message)
|
||||||
|
}
|
||||||
|
}
|
55
vendor/github.com/aws/aws-sdk-go/aws/csm/metric_chan.go
generated
vendored
Normal file
55
vendor/github.com/aws/aws-sdk-go/aws/csm/metric_chan.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package csm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
runningEnum = iota
|
||||||
|
pausedEnum
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// MetricsChannelSize of metrics to hold in the channel
|
||||||
|
MetricsChannelSize = 100
|
||||||
|
)
|
||||||
|
|
||||||
|
type metricChan struct {
|
||||||
|
ch chan metric
|
||||||
|
paused *int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMetricChan(size int) metricChan {
|
||||||
|
return metricChan{
|
||||||
|
ch: make(chan metric, size),
|
||||||
|
paused: new(int64),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ch *metricChan) Pause() {
|
||||||
|
atomic.StoreInt64(ch.paused, pausedEnum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ch *metricChan) Continue() {
|
||||||
|
atomic.StoreInt64(ch.paused, runningEnum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ch *metricChan) IsPaused() bool {
|
||||||
|
v := atomic.LoadInt64(ch.paused)
|
||||||
|
return v == pausedEnum
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push will push metrics to the metric channel if the channel
|
||||||
|
// is not paused
|
||||||
|
func (ch *metricChan) Push(m metric) bool {
|
||||||
|
if ch.IsPaused() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ch.ch <- m:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
26
vendor/github.com/aws/aws-sdk-go/aws/csm/metric_exception.go
generated
vendored
Normal file
26
vendor/github.com/aws/aws-sdk-go/aws/csm/metric_exception.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package csm
|
||||||
|
|
||||||
|
type metricException interface {
|
||||||
|
Exception() string
|
||||||
|
Message() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type requestException struct {
|
||||||
|
exception string
|
||||||
|
message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e requestException) Exception() string {
|
||||||
|
return e.exception
|
||||||
|
}
|
||||||
|
func (e requestException) Message() string {
|
||||||
|
return e.message
|
||||||
|
}
|
||||||
|
|
||||||
|
type awsException struct {
|
||||||
|
requestException
|
||||||
|
}
|
||||||
|
|
||||||
|
type sdkException struct {
|
||||||
|
requestException
|
||||||
|
}
|
264
vendor/github.com/aws/aws-sdk-go/aws/csm/reporter.go
generated
vendored
Normal file
264
vendor/github.com/aws/aws-sdk-go/aws/csm/reporter.go
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
package csm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reporter will gather metrics of API requests made and
|
||||||
|
// send those metrics to the CSM endpoint.
|
||||||
|
type Reporter struct {
|
||||||
|
clientID string
|
||||||
|
url string
|
||||||
|
conn net.Conn
|
||||||
|
metricsCh metricChan
|
||||||
|
done chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
sender *Reporter
|
||||||
|
)
|
||||||
|
|
||||||
|
func connect(url string) error {
|
||||||
|
const network = "udp"
|
||||||
|
if err := sender.connect(network, url); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if sender.done == nil {
|
||||||
|
sender.done = make(chan struct{})
|
||||||
|
go sender.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newReporter(clientID, url string) *Reporter {
|
||||||
|
return &Reporter{
|
||||||
|
clientID: clientID,
|
||||||
|
url: url,
|
||||||
|
metricsCh: newMetricChan(MetricsChannelSize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rep *Reporter) sendAPICallAttemptMetric(r *request.Request) {
|
||||||
|
if rep == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
creds, _ := r.Config.Credentials.Get()
|
||||||
|
|
||||||
|
m := metric{
|
||||||
|
ClientID: aws.String(rep.clientID),
|
||||||
|
API: aws.String(r.Operation.Name),
|
||||||
|
Service: aws.String(r.ClientInfo.ServiceID),
|
||||||
|
Timestamp: (*metricTime)(&now),
|
||||||
|
UserAgent: aws.String(r.HTTPRequest.Header.Get("User-Agent")),
|
||||||
|
Region: r.Config.Region,
|
||||||
|
Type: aws.String("ApiCallAttempt"),
|
||||||
|
Version: aws.Int(1),
|
||||||
|
|
||||||
|
XAmzRequestID: aws.String(r.RequestID),
|
||||||
|
|
||||||
|
AttemptLatency: aws.Int(int(now.Sub(r.AttemptTime).Nanoseconds() / int64(time.Millisecond))),
|
||||||
|
AccessKey: aws.String(creds.AccessKeyID),
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
m.HTTPStatusCode = aws.Int(r.HTTPResponse.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Error != nil {
|
||||||
|
if awserr, ok := r.Error.(awserr.Error); ok {
|
||||||
|
m.SetException(getMetricException(awserr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.TruncateFields()
|
||||||
|
rep.metricsCh.Push(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMetricException(err awserr.Error) metricException {
|
||||||
|
msg := err.Error()
|
||||||
|
code := err.Code()
|
||||||
|
|
||||||
|
switch code {
|
||||||
|
case request.ErrCodeRequestError,
|
||||||
|
request.ErrCodeSerialization,
|
||||||
|
request.CanceledErrorCode:
|
||||||
|
return sdkException{
|
||||||
|
requestException{exception: code, message: msg},
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return awsException{
|
||||||
|
requestException{exception: code, message: msg},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rep *Reporter) sendAPICallMetric(r *request.Request) {
|
||||||
|
if rep == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
m := metric{
|
||||||
|
ClientID: aws.String(rep.clientID),
|
||||||
|
API: aws.String(r.Operation.Name),
|
||||||
|
Service: aws.String(r.ClientInfo.ServiceID),
|
||||||
|
Timestamp: (*metricTime)(&now),
|
||||||
|
UserAgent: aws.String(r.HTTPRequest.Header.Get("User-Agent")),
|
||||||
|
Type: aws.String("ApiCall"),
|
||||||
|
AttemptCount: aws.Int(r.RetryCount + 1),
|
||||||
|
Region: r.Config.Region,
|
||||||
|
Latency: aws.Int(int(time.Since(r.Time) / time.Millisecond)),
|
||||||
|
XAmzRequestID: aws.String(r.RequestID),
|
||||||
|
MaxRetriesExceeded: aws.Int(boolIntValue(r.RetryCount >= r.MaxRetries())),
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
m.FinalHTTPStatusCode = aws.Int(r.HTTPResponse.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Error != nil {
|
||||||
|
if awserr, ok := r.Error.(awserr.Error); ok {
|
||||||
|
m.SetFinalException(getMetricException(awserr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.TruncateFields()
|
||||||
|
|
||||||
|
// TODO: Probably want to figure something out for logging dropped
|
||||||
|
// metrics
|
||||||
|
rep.metricsCh.Push(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rep *Reporter) connect(network, url string) error {
|
||||||
|
if rep.conn != nil {
|
||||||
|
rep.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.Dial(network, url)
|
||||||
|
if err != nil {
|
||||||
|
return awserr.New("UDPError", "Could not connect", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rep.conn = conn
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rep *Reporter) close() {
|
||||||
|
if rep.done != nil {
|
||||||
|
close(rep.done)
|
||||||
|
}
|
||||||
|
|
||||||
|
rep.metricsCh.Pause()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rep *Reporter) start() {
|
||||||
|
defer func() {
|
||||||
|
rep.metricsCh.Pause()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-rep.done:
|
||||||
|
rep.done = nil
|
||||||
|
return
|
||||||
|
case m := <-rep.metricsCh.ch:
|
||||||
|
// TODO: What to do with this error? Probably should just log
|
||||||
|
b, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
rep.conn.Write(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pause will pause the metric channel preventing any new metrics from being
|
||||||
|
// added. It is safe to call concurrently with other calls to Pause, but if
|
||||||
|
// called concurently with Continue can lead to unexpected state.
|
||||||
|
func (rep *Reporter) Pause() {
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
|
||||||
|
if rep == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rep.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue will reopen the metric channel and allow for monitoring to be
|
||||||
|
// resumed. It is safe to call concurrently with other calls to Continue, but
|
||||||
|
// if called concurently with Pause can lead to unexpected state.
|
||||||
|
func (rep *Reporter) Continue() {
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
if rep == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rep.metricsCh.IsPaused() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rep.metricsCh.Continue()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client side metric handler names
|
||||||
|
const (
|
||||||
|
APICallMetricHandlerName = "awscsm.SendAPICallMetric"
|
||||||
|
APICallAttemptMetricHandlerName = "awscsm.SendAPICallAttemptMetric"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InjectHandlers will will enable client side metrics and inject the proper
|
||||||
|
// handlers to handle how metrics are sent.
|
||||||
|
//
|
||||||
|
// InjectHandlers is NOT safe to call concurrently. Calling InjectHandlers
|
||||||
|
// multiple times may lead to unexpected behavior, (e.g. duplicate metrics).
|
||||||
|
//
|
||||||
|
// // Start must be called in order to inject the correct handlers
|
||||||
|
// r, err := csm.Start("clientID", "127.0.0.1:8094")
|
||||||
|
// if err != nil {
|
||||||
|
// panic(fmt.Errorf("expected no error, but received %v", err))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// sess := session.NewSession()
|
||||||
|
// r.InjectHandlers(&sess.Handlers)
|
||||||
|
//
|
||||||
|
// // create a new service client with our client side metric session
|
||||||
|
// svc := s3.New(sess)
|
||||||
|
func (rep *Reporter) InjectHandlers(handlers *request.Handlers) {
|
||||||
|
if rep == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers.Complete.PushFrontNamed(request.NamedHandler{
|
||||||
|
Name: APICallMetricHandlerName,
|
||||||
|
Fn: rep.sendAPICallMetric,
|
||||||
|
})
|
||||||
|
|
||||||
|
handlers.CompleteAttempt.PushFrontNamed(request.NamedHandler{
|
||||||
|
Name: APICallAttemptMetricHandlerName,
|
||||||
|
Fn: rep.sendAPICallAttemptMetric,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// boolIntValue return 1 for true and 0 for false.
|
||||||
|
func boolIntValue(b bool) int {
|
||||||
|
if b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
207
vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go
generated
vendored
Normal file
207
vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go
generated
vendored
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
// Package defaults is a collection of helpers to retrieve the SDK's default
|
||||||
|
// configuration and handlers.
|
||||||
|
//
|
||||||
|
// Generally this package shouldn't be used directly, but session.Session
|
||||||
|
// instead. This package is useful when you need to reset the defaults
|
||||||
|
// of a session or service client to the SDK defaults before setting
|
||||||
|
// additional parameters.
|
||||||
|
package defaults
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"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/credentials/ec2rolecreds"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials/endpointcreds"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/shareddefaults"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Defaults provides a collection of default values for SDK clients.
|
||||||
|
type Defaults struct {
|
||||||
|
Config *aws.Config
|
||||||
|
Handlers request.Handlers
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the SDK's default values with Config and handlers pre-configured.
|
||||||
|
func Get() Defaults {
|
||||||
|
cfg := Config()
|
||||||
|
handlers := Handlers()
|
||||||
|
cfg.Credentials = CredChain(cfg, handlers)
|
||||||
|
|
||||||
|
return Defaults{
|
||||||
|
Config: cfg,
|
||||||
|
Handlers: handlers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config returns the default configuration without credentials.
|
||||||
|
// To retrieve a config with credentials also included use
|
||||||
|
// `defaults.Get().Config` instead.
|
||||||
|
//
|
||||||
|
// Generally you shouldn't need to use this method directly, but
|
||||||
|
// is available if you need to reset the configuration of an
|
||||||
|
// existing service client or session.
|
||||||
|
func Config() *aws.Config {
|
||||||
|
return aws.NewConfig().
|
||||||
|
WithCredentials(credentials.AnonymousCredentials).
|
||||||
|
WithRegion(os.Getenv("AWS_REGION")).
|
||||||
|
WithHTTPClient(http.DefaultClient).
|
||||||
|
WithMaxRetries(aws.UseServiceDefaultRetries).
|
||||||
|
WithLogger(aws.NewDefaultLogger()).
|
||||||
|
WithLogLevel(aws.LogOff).
|
||||||
|
WithEndpointResolver(endpoints.DefaultResolver())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handlers returns the default request handlers.
|
||||||
|
//
|
||||||
|
// Generally you shouldn't need to use this method directly, but
|
||||||
|
// is available if you need to reset the request handlers of an
|
||||||
|
// existing service client or session.
|
||||||
|
func Handlers() request.Handlers {
|
||||||
|
var handlers request.Handlers
|
||||||
|
|
||||||
|
handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||||
|
handlers.Validate.AfterEachFn = request.HandlerListStopOnError
|
||||||
|
handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler)
|
||||||
|
handlers.Build.PushBackNamed(corehandlers.AddHostExecEnvUserAgentHander)
|
||||||
|
handlers.Build.AfterEachFn = request.HandlerListStopOnError
|
||||||
|
handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
||||||
|
handlers.Send.PushBackNamed(corehandlers.ValidateReqSigHandler)
|
||||||
|
handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||||
|
handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||||
|
handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
|
||||||
|
|
||||||
|
return handlers
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredChain returns the default credential chain.
|
||||||
|
//
|
||||||
|
// Generally you shouldn't need to use this method directly, but
|
||||||
|
// is available if you need to reset the credentials of an
|
||||||
|
// existing service client or session's Config.
|
||||||
|
func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials {
|
||||||
|
return credentials.NewCredentials(&credentials.ChainProvider{
|
||||||
|
VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors),
|
||||||
|
Providers: CredProviders(cfg, handlers),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredProviders returns the slice of providers used in
|
||||||
|
// the default credential chain.
|
||||||
|
//
|
||||||
|
// For applications that need to use some other provider (for example use
|
||||||
|
// different environment variables for legacy reasons) but still fall back
|
||||||
|
// on the default chain of providers. This allows that default chaint to be
|
||||||
|
// automatically updated
|
||||||
|
func CredProviders(cfg *aws.Config, handlers request.Handlers) []credentials.Provider {
|
||||||
|
return []credentials.Provider{
|
||||||
|
&credentials.EnvProvider{},
|
||||||
|
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||||
|
RemoteCredProvider(*cfg, handlers),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
httpProviderAuthorizationEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN"
|
||||||
|
httpProviderEnvVar = "AWS_CONTAINER_CREDENTIALS_FULL_URI"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RemoteCredProvider returns a credentials provider for the default remote
|
||||||
|
// endpoints such as EC2 or ECS Roles.
|
||||||
|
func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||||
|
if u := os.Getenv(httpProviderEnvVar); len(u) > 0 {
|
||||||
|
return localHTTPCredProvider(cfg, handlers, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
if uri := os.Getenv(shareddefaults.ECSCredsProviderEnvVar); len(uri) > 0 {
|
||||||
|
u := fmt.Sprintf("%s%s", shareddefaults.ECSContainerCredentialsURI, uri)
|
||||||
|
return httpCredProvider(cfg, handlers, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ec2RoleProvider(cfg, handlers)
|
||||||
|
}
|
||||||
|
|
||||||
|
var lookupHostFn = net.LookupHost
|
||||||
|
|
||||||
|
func isLoopbackHost(host string) (bool, error) {
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if ip != nil {
|
||||||
|
return ip.IsLoopback(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Host is not an ip, perform lookup
|
||||||
|
addrs, err := lookupHostFn(host)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if !net.ParseIP(addr).IsLoopback() {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func localHTTPCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider {
|
||||||
|
var errMsg string
|
||||||
|
|
||||||
|
parsed, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
errMsg = fmt.Sprintf("invalid URL, %v", err)
|
||||||
|
} else {
|
||||||
|
host := aws.URLHostname(parsed)
|
||||||
|
if len(host) == 0 {
|
||||||
|
errMsg = "unable to parse host from local HTTP cred provider URL"
|
||||||
|
} else if isLoopback, loopbackErr := isLoopbackHost(host); loopbackErr != nil {
|
||||||
|
errMsg = fmt.Sprintf("failed to resolve host %q, %v", host, loopbackErr)
|
||||||
|
} else if !isLoopback {
|
||||||
|
errMsg = fmt.Sprintf("invalid endpoint host, %q, only loopback hosts are allowed.", host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errMsg) > 0 {
|
||||||
|
if cfg.Logger != nil {
|
||||||
|
cfg.Logger.Log("Ignoring, HTTP credential provider", errMsg, err)
|
||||||
|
}
|
||||||
|
return credentials.ErrorProvider{
|
||||||
|
Err: awserr.New("CredentialsEndpointError", errMsg, err),
|
||||||
|
ProviderName: endpointcreds.ProviderName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpCredProvider(cfg, handlers, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider {
|
||||||
|
return endpointcreds.NewProviderClient(cfg, handlers, u,
|
||||||
|
func(p *endpointcreds.Provider) {
|
||||||
|
p.ExpiryWindow = 5 * time.Minute
|
||||||
|
p.AuthorizationToken = os.Getenv(httpProviderAuthorizationEnvVar)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ec2RoleProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||||
|
resolver := cfg.EndpointResolver
|
||||||
|
if resolver == nil {
|
||||||
|
resolver = endpoints.DefaultResolver()
|
||||||
|
}
|
||||||
|
|
||||||
|
e, _ := resolver.EndpointFor(endpoints.Ec2metadataServiceID, "")
|
||||||
|
return &ec2rolecreds.EC2RoleProvider{
|
||||||
|
Client: ec2metadata.NewClient(cfg, handlers, e.URL, e.SigningRegion),
|
||||||
|
ExpiryWindow: 5 * time.Minute,
|
||||||
|
}
|
||||||
|
}
|
27
vendor/github.com/aws/aws-sdk-go/aws/defaults/shared_config.go
generated
vendored
Normal file
27
vendor/github.com/aws/aws-sdk-go/aws/defaults/shared_config.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package defaults
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/internal/shareddefaults"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SharedCredentialsFilename returns the SDK's default file path
|
||||||
|
// for the shared credentials file.
|
||||||
|
//
|
||||||
|
// Builds the shared config file path based on the OS's platform.
|
||||||
|
//
|
||||||
|
// - Linux/Unix: $HOME/.aws/credentials
|
||||||
|
// - Windows: %USERPROFILE%\.aws\credentials
|
||||||
|
func SharedCredentialsFilename() string {
|
||||||
|
return shareddefaults.SharedCredentialsFilename()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SharedConfigFilename returns the SDK's default file path for
|
||||||
|
// the shared config file.
|
||||||
|
//
|
||||||
|
// Builds the shared config file path based on the OS's platform.
|
||||||
|
//
|
||||||
|
// - Linux/Unix: $HOME/.aws/config
|
||||||
|
// - Windows: %USERPROFILE%\.aws\config
|
||||||
|
func SharedConfigFilename() string {
|
||||||
|
return shareddefaults.SharedConfigFilename()
|
||||||
|
}
|
56
vendor/github.com/aws/aws-sdk-go/aws/doc.go
generated
vendored
Normal file
56
vendor/github.com/aws/aws-sdk-go/aws/doc.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Package aws provides the core SDK's utilities and shared types. Use this package's
|
||||||
|
// utilities to simplify setting and reading API operations parameters.
|
||||||
|
//
|
||||||
|
// Value and Pointer Conversion Utilities
|
||||||
|
//
|
||||||
|
// This package includes a helper conversion utility for each scalar type the SDK's
|
||||||
|
// API use. These utilities make getting a pointer of the scalar, and dereferencing
|
||||||
|
// a pointer easier.
|
||||||
|
//
|
||||||
|
// Each conversion utility comes in two forms. Value to Pointer and Pointer to Value.
|
||||||
|
// The Pointer to value will safely dereference the pointer and return its value.
|
||||||
|
// If the pointer was nil, the scalar's zero value will be returned.
|
||||||
|
//
|
||||||
|
// The value to pointer functions will be named after the scalar type. So get a
|
||||||
|
// *string from a string value use the "String" function. This makes it easy to
|
||||||
|
// to get pointer of a literal string value, because getting the address of a
|
||||||
|
// literal requires assigning the value to a variable first.
|
||||||
|
//
|
||||||
|
// var strPtr *string
|
||||||
|
//
|
||||||
|
// // Without the SDK's conversion functions
|
||||||
|
// str := "my string"
|
||||||
|
// strPtr = &str
|
||||||
|
//
|
||||||
|
// // With the SDK's conversion functions
|
||||||
|
// strPtr = aws.String("my string")
|
||||||
|
//
|
||||||
|
// // Convert *string to string value
|
||||||
|
// str = aws.StringValue(strPtr)
|
||||||
|
//
|
||||||
|
// In addition to scalars the aws package also includes conversion utilities for
|
||||||
|
// map and slice for commonly types used in API parameters. The map and slice
|
||||||
|
// conversion functions use similar naming pattern as the scalar conversion
|
||||||
|
// functions.
|
||||||
|
//
|
||||||
|
// var strPtrs []*string
|
||||||
|
// var strs []string = []string{"Go", "Gophers", "Go"}
|
||||||
|
//
|
||||||
|
// // Convert []string to []*string
|
||||||
|
// strPtrs = aws.StringSlice(strs)
|
||||||
|
//
|
||||||
|
// // Convert []*string to []string
|
||||||
|
// strs = aws.StringValueSlice(strPtrs)
|
||||||
|
//
|
||||||
|
// SDK Default HTTP Client
|
||||||
|
//
|
||||||
|
// The SDK will use the http.DefaultClient if a HTTP client is not provided to
|
||||||
|
// the SDK's Session, or service client constructor. This means that if the
|
||||||
|
// http.DefaultClient is modified by other components of your application the
|
||||||
|
// modifications will be picked up by the SDK as well.
|
||||||
|
//
|
||||||
|
// In some cases this might be intended, but it is a better practice to create
|
||||||
|
// a custom HTTP Client to share explicitly through your application. You can
|
||||||
|
// configure the SDK to use the custom HTTP Client by setting the HTTPClient
|
||||||
|
// value of the SDK's Config type when creating a Session or service client.
|
||||||
|
package aws
|
250
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go
generated
vendored
Normal file
250
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go
generated
vendored
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
package ec2metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"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/internal/sdkuri"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getToken uses the duration to return a token for EC2 metadata service,
|
||||||
|
// or an error if the request failed.
|
||||||
|
func (c *EC2Metadata) getToken(ctx aws.Context, duration time.Duration) (tokenOutput, error) {
|
||||||
|
op := &request.Operation{
|
||||||
|
Name: "GetToken",
|
||||||
|
HTTPMethod: "PUT",
|
||||||
|
HTTPPath: "/latest/api/token",
|
||||||
|
}
|
||||||
|
|
||||||
|
var output tokenOutput
|
||||||
|
req := c.NewRequest(op, nil, &output)
|
||||||
|
req.SetContext(ctx)
|
||||||
|
|
||||||
|
// remove the fetch token handler from the request handlers to avoid infinite recursion
|
||||||
|
req.Handlers.Sign.RemoveByName(fetchTokenHandlerName)
|
||||||
|
|
||||||
|
// Swap the unmarshalMetadataHandler with unmarshalTokenHandler on this request.
|
||||||
|
req.Handlers.Unmarshal.Swap(unmarshalMetadataHandlerName, unmarshalTokenHandler)
|
||||||
|
|
||||||
|
ttl := strconv.FormatInt(int64(duration/time.Second), 10)
|
||||||
|
req.HTTPRequest.Header.Set(ttlHeader, ttl)
|
||||||
|
|
||||||
|
err := req.Send()
|
||||||
|
|
||||||
|
// Errors with bad request status should be returned.
|
||||||
|
if err != nil {
|
||||||
|
err = awserr.NewRequestFailure(
|
||||||
|
awserr.New(req.HTTPResponse.Status, http.StatusText(req.HTTPResponse.StatusCode), err),
|
||||||
|
req.HTTPResponse.StatusCode, req.RequestID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return output, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetadata uses the path provided to request information from the EC2
|
||||||
|
// instance metadata service. The content will be returned as a string, or
|
||||||
|
// error if the request failed.
|
||||||
|
func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
||||||
|
return c.GetMetadataWithContext(aws.BackgroundContext(), p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetadataWithContext uses the path provided to request information from the EC2
|
||||||
|
// instance metadata service. The content will be returned as a string, or
|
||||||
|
// error if the request failed.
|
||||||
|
func (c *EC2Metadata) GetMetadataWithContext(ctx aws.Context, p string) (string, error) {
|
||||||
|
op := &request.Operation{
|
||||||
|
Name: "GetMetadata",
|
||||||
|
HTTPMethod: "GET",
|
||||||
|
HTTPPath: sdkuri.PathJoin("/latest/meta-data", p),
|
||||||
|
}
|
||||||
|
output := &metadataOutput{}
|
||||||
|
|
||||||
|
req := c.NewRequest(op, nil, output)
|
||||||
|
|
||||||
|
req.SetContext(ctx)
|
||||||
|
|
||||||
|
err := req.Send()
|
||||||
|
return output.Content, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserData returns the userdata that was configured for the service. If
|
||||||
|
// there is no user-data setup for the EC2 instance a "NotFoundError" error
|
||||||
|
// code will be returned.
|
||||||
|
func (c *EC2Metadata) GetUserData() (string, error) {
|
||||||
|
return c.GetUserDataWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserDataWithContext returns the userdata that was configured for the service. If
|
||||||
|
// there is no user-data setup for the EC2 instance a "NotFoundError" error
|
||||||
|
// code will be returned.
|
||||||
|
func (c *EC2Metadata) GetUserDataWithContext(ctx aws.Context) (string, error) {
|
||||||
|
op := &request.Operation{
|
||||||
|
Name: "GetUserData",
|
||||||
|
HTTPMethod: "GET",
|
||||||
|
HTTPPath: "/latest/user-data",
|
||||||
|
}
|
||||||
|
|
||||||
|
output := &metadataOutput{}
|
||||||
|
req := c.NewRequest(op, nil, output)
|
||||||
|
req.SetContext(ctx)
|
||||||
|
|
||||||
|
err := req.Send()
|
||||||
|
return output.Content, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDynamicData uses the path provided to request information from the EC2
|
||||||
|
// instance metadata service for dynamic data. The content will be returned
|
||||||
|
// as a string, or error if the request failed.
|
||||||
|
func (c *EC2Metadata) GetDynamicData(p string) (string, error) {
|
||||||
|
return c.GetDynamicDataWithContext(aws.BackgroundContext(), p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDynamicDataWithContext uses the path provided to request information from the EC2
|
||||||
|
// instance metadata service for dynamic data. The content will be returned
|
||||||
|
// as a string, or error if the request failed.
|
||||||
|
func (c *EC2Metadata) GetDynamicDataWithContext(ctx aws.Context, p string) (string, error) {
|
||||||
|
op := &request.Operation{
|
||||||
|
Name: "GetDynamicData",
|
||||||
|
HTTPMethod: "GET",
|
||||||
|
HTTPPath: sdkuri.PathJoin("/latest/dynamic", p),
|
||||||
|
}
|
||||||
|
|
||||||
|
output := &metadataOutput{}
|
||||||
|
req := c.NewRequest(op, nil, output)
|
||||||
|
req.SetContext(ctx)
|
||||||
|
|
||||||
|
err := req.Send()
|
||||||
|
return output.Content, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInstanceIdentityDocument retrieves an identity document describing an
|
||||||
|
// instance. Error is returned if the request fails or is unable to parse
|
||||||
|
// the response.
|
||||||
|
func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument, error) {
|
||||||
|
return c.GetInstanceIdentityDocumentWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInstanceIdentityDocumentWithContext retrieves an identity document describing an
|
||||||
|
// instance. Error is returned if the request fails or is unable to parse
|
||||||
|
// the response.
|
||||||
|
func (c *EC2Metadata) GetInstanceIdentityDocumentWithContext(ctx aws.Context) (EC2InstanceIdentityDocument, error) {
|
||||||
|
resp, err := c.GetDynamicDataWithContext(ctx, "instance-identity/document")
|
||||||
|
if err != nil {
|
||||||
|
return EC2InstanceIdentityDocument{},
|
||||||
|
awserr.New("EC2MetadataRequestError",
|
||||||
|
"failed to get EC2 instance identity document", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doc := EC2InstanceIdentityDocument{}
|
||||||
|
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&doc); err != nil {
|
||||||
|
return EC2InstanceIdentityDocument{},
|
||||||
|
awserr.New(request.ErrCodeSerialization,
|
||||||
|
"failed to decode EC2 instance identity document", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IAMInfo retrieves IAM info from the metadata API
|
||||||
|
func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) {
|
||||||
|
return c.IAMInfoWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// IAMInfoWithContext retrieves IAM info from the metadata API
|
||||||
|
func (c *EC2Metadata) IAMInfoWithContext(ctx aws.Context) (EC2IAMInfo, error) {
|
||||||
|
resp, err := c.GetMetadataWithContext(ctx, "iam/info")
|
||||||
|
if err != nil {
|
||||||
|
return EC2IAMInfo{},
|
||||||
|
awserr.New("EC2MetadataRequestError",
|
||||||
|
"failed to get EC2 IAM info", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info := EC2IAMInfo{}
|
||||||
|
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&info); err != nil {
|
||||||
|
return EC2IAMInfo{},
|
||||||
|
awserr.New(request.ErrCodeSerialization,
|
||||||
|
"failed to decode EC2 IAM info", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Code != "Success" {
|
||||||
|
errMsg := fmt.Sprintf("failed to get EC2 IAM Info (%s)", info.Code)
|
||||||
|
return EC2IAMInfo{},
|
||||||
|
awserr.New("EC2MetadataError", errMsg, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Region returns the region the instance is running in.
|
||||||
|
func (c *EC2Metadata) Region() (string, error) {
|
||||||
|
return c.RegionWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegionWithContext returns the region the instance is running in.
|
||||||
|
func (c *EC2Metadata) RegionWithContext(ctx aws.Context) (string, error) {
|
||||||
|
ec2InstanceIdentityDocument, err := c.GetInstanceIdentityDocumentWithContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// extract region from the ec2InstanceIdentityDocument
|
||||||
|
region := ec2InstanceIdentityDocument.Region
|
||||||
|
if len(region) == 0 {
|
||||||
|
return "", awserr.New("EC2MetadataError", "invalid region received for ec2metadata instance", nil)
|
||||||
|
}
|
||||||
|
// returns region
|
||||||
|
return region, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Available returns if the application has access to the EC2 Metadata service.
|
||||||
|
// Can be used to determine if application is running within an EC2 Instance and
|
||||||
|
// the metadata service is available.
|
||||||
|
func (c *EC2Metadata) Available() bool {
|
||||||
|
return c.AvailableWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// AvailableWithContext returns if the application has access to the EC2 Metadata service.
|
||||||
|
// Can be used to determine if application is running within an EC2 Instance and
|
||||||
|
// the metadata service is available.
|
||||||
|
func (c *EC2Metadata) AvailableWithContext(ctx aws.Context) bool {
|
||||||
|
if _, err := c.GetMetadataWithContext(ctx, "instance-id"); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// An EC2IAMInfo provides the shape for unmarshaling
|
||||||
|
// an IAM info from the metadata API
|
||||||
|
type EC2IAMInfo struct {
|
||||||
|
Code string
|
||||||
|
LastUpdated time.Time
|
||||||
|
InstanceProfileArn string
|
||||||
|
InstanceProfileID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// An EC2InstanceIdentityDocument provides the shape for unmarshaling
|
||||||
|
// an instance identity document
|
||||||
|
type EC2InstanceIdentityDocument struct {
|
||||||
|
DevpayProductCodes []string `json:"devpayProductCodes"`
|
||||||
|
MarketplaceProductCodes []string `json:"marketplaceProductCodes"`
|
||||||
|
AvailabilityZone string `json:"availabilityZone"`
|
||||||
|
PrivateIP string `json:"privateIp"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Region string `json:"region"`
|
||||||
|
InstanceID string `json:"instanceId"`
|
||||||
|
BillingProducts []string `json:"billingProducts"`
|
||||||
|
InstanceType string `json:"instanceType"`
|
||||||
|
AccountID string `json:"accountId"`
|
||||||
|
PendingTime time.Time `json:"pendingTime"`
|
||||||
|
ImageID string `json:"imageId"`
|
||||||
|
KernelID string `json:"kernelId"`
|
||||||
|
RamdiskID string `json:"ramdiskId"`
|
||||||
|
Architecture string `json:"architecture"`
|
||||||
|
}
|
245
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go
generated
vendored
Normal file
245
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go
generated
vendored
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
// Package ec2metadata provides the client for making API calls to the
|
||||||
|
// EC2 Metadata service.
|
||||||
|
//
|
||||||
|
// This package's client can be disabled completely by setting the environment
|
||||||
|
// variable "AWS_EC2_METADATA_DISABLED=true". This environment variable set to
|
||||||
|
// true instructs the SDK to disable the EC2 Metadata client. The client cannot
|
||||||
|
// be used while the environment variable is set to true, (case insensitive).
|
||||||
|
//
|
||||||
|
// The endpoint of the EC2 IMDS client can be configured via the environment
|
||||||
|
// variable, AWS_EC2_METADATA_SERVICE_ENDPOINT when creating the client with a
|
||||||
|
// Session. See aws/session#Options.EC2IMDSEndpoint for more details.
|
||||||
|
package ec2metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ServiceName is the name of the service.
|
||||||
|
ServiceName = "ec2metadata"
|
||||||
|
disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED"
|
||||||
|
|
||||||
|
// Headers for Token and TTL
|
||||||
|
ttlHeader = "x-aws-ec2-metadata-token-ttl-seconds"
|
||||||
|
tokenHeader = "x-aws-ec2-metadata-token"
|
||||||
|
|
||||||
|
// Named Handler constants
|
||||||
|
fetchTokenHandlerName = "FetchTokenHandler"
|
||||||
|
unmarshalMetadataHandlerName = "unmarshalMetadataHandler"
|
||||||
|
unmarshalTokenHandlerName = "unmarshalTokenHandler"
|
||||||
|
enableTokenProviderHandlerName = "enableTokenProviderHandler"
|
||||||
|
|
||||||
|
// TTL constants
|
||||||
|
defaultTTL = 21600 * time.Second
|
||||||
|
ttlExpirationWindow = 30 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
// A EC2Metadata is an EC2 Metadata service Client.
|
||||||
|
type EC2Metadata struct {
|
||||||
|
*client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new instance of the EC2Metadata client with a session.
|
||||||
|
// This client is safe to use across multiple goroutines.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// // Create a EC2Metadata client from just a session.
|
||||||
|
// svc := ec2metadata.New(mySession)
|
||||||
|
//
|
||||||
|
// // Create a EC2Metadata client with additional configuration
|
||||||
|
// svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody))
|
||||||
|
func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata {
|
||||||
|
c := p.ClientConfig(ServiceName, cfgs...)
|
||||||
|
return NewClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a new EC2Metadata client. Should be used to create
|
||||||
|
// a client when not using a session. Generally using just New with a session
|
||||||
|
// is preferred.
|
||||||
|
//
|
||||||
|
// Will remove the URL path from the endpoint provided to ensure the EC2 IMDS
|
||||||
|
// client is able to communicate with the EC2 IMDS API.
|
||||||
|
//
|
||||||
|
// If an unmodified HTTP client is provided from the stdlib default, or no client
|
||||||
|
// the EC2RoleProvider's EC2Metadata HTTP client's timeout will be shortened.
|
||||||
|
// To disable this set Config.EC2MetadataDisableTimeoutOverride to false. Enabled by default.
|
||||||
|
func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string, opts ...func(*client.Client)) *EC2Metadata {
|
||||||
|
if !aws.BoolValue(cfg.EC2MetadataDisableTimeoutOverride) && httpClientZero(cfg.HTTPClient) {
|
||||||
|
// If the http client is unmodified and this feature is not disabled
|
||||||
|
// set custom timeouts for EC2Metadata requests.
|
||||||
|
cfg.HTTPClient = &http.Client{
|
||||||
|
// use a shorter timeout than default because the metadata
|
||||||
|
// service is local if it is running, and to fail faster
|
||||||
|
// if not running on an ec2 instance.
|
||||||
|
Timeout: 1 * time.Second,
|
||||||
|
}
|
||||||
|
// max number of retries on the client operation
|
||||||
|
cfg.MaxRetries = aws.Int(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if u, err := url.Parse(endpoint); err == nil {
|
||||||
|
// Remove path from the endpoint since it will be added by requests.
|
||||||
|
// This is an artifact of the SDK adding `/latest` to the endpoint for
|
||||||
|
// EC2 IMDS, but this is now moved to the operation definition.
|
||||||
|
u.Path = ""
|
||||||
|
u.RawPath = ""
|
||||||
|
endpoint = u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := &EC2Metadata{
|
||||||
|
Client: client.New(
|
||||||
|
cfg,
|
||||||
|
metadata.ClientInfo{
|
||||||
|
ServiceName: ServiceName,
|
||||||
|
ServiceID: ServiceName,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
APIVersion: "latest",
|
||||||
|
},
|
||||||
|
handlers,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
// token provider instance
|
||||||
|
tp := newTokenProvider(svc, defaultTTL)
|
||||||
|
|
||||||
|
// NamedHandler for fetching token
|
||||||
|
svc.Handlers.Sign.PushBackNamed(request.NamedHandler{
|
||||||
|
Name: fetchTokenHandlerName,
|
||||||
|
Fn: tp.fetchTokenHandler,
|
||||||
|
})
|
||||||
|
// NamedHandler for enabling token provider
|
||||||
|
svc.Handlers.Complete.PushBackNamed(request.NamedHandler{
|
||||||
|
Name: enableTokenProviderHandlerName,
|
||||||
|
Fn: tp.enableTokenProviderHandler,
|
||||||
|
})
|
||||||
|
|
||||||
|
svc.Handlers.Unmarshal.PushBackNamed(unmarshalHandler)
|
||||||
|
svc.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||||
|
svc.Handlers.Validate.Clear()
|
||||||
|
svc.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||||
|
|
||||||
|
// Disable the EC2 Metadata service if the environment variable is set.
|
||||||
|
// This short-circuits the service's functionality to always fail to send
|
||||||
|
// requests.
|
||||||
|
if strings.ToLower(os.Getenv(disableServiceEnvVar)) == "true" {
|
||||||
|
svc.Handlers.Send.SwapNamed(request.NamedHandler{
|
||||||
|
Name: corehandlers.SendHandler.Name,
|
||||||
|
Fn: func(r *request.Request) {
|
||||||
|
r.HTTPResponse = &http.Response{
|
||||||
|
Header: http.Header{},
|
||||||
|
}
|
||||||
|
r.Error = awserr.New(
|
||||||
|
request.CanceledErrorCode,
|
||||||
|
"EC2 IMDS access disabled via "+disableServiceEnvVar+" env var",
|
||||||
|
nil)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add additional options to the service config
|
||||||
|
for _, option := range opts {
|
||||||
|
option(svc.Client)
|
||||||
|
}
|
||||||
|
return svc
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpClientZero(c *http.Client) bool {
|
||||||
|
return c == nil || (c.Transport == nil && c.CheckRedirect == nil && c.Jar == nil && c.Timeout == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
type metadataOutput struct {
|
||||||
|
Content string
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenOutput struct {
|
||||||
|
Token string
|
||||||
|
TTL time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshal token handler is used to parse the response of a getToken operation
|
||||||
|
var unmarshalTokenHandler = request.NamedHandler{
|
||||||
|
Name: unmarshalTokenHandlerName,
|
||||||
|
Fn: func(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
var b bytes.Buffer
|
||||||
|
if _, err := io.Copy(&b, r.HTTPResponse.Body); err != nil {
|
||||||
|
r.Error = awserr.NewRequestFailure(awserr.New(request.ErrCodeSerialization,
|
||||||
|
"unable to unmarshal EC2 metadata response", err), r.HTTPResponse.StatusCode, r.RequestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := r.HTTPResponse.Header.Get(ttlHeader)
|
||||||
|
data, ok := r.Data.(*tokenOutput)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Token = b.String()
|
||||||
|
// TTL is in seconds
|
||||||
|
i, err := strconv.ParseInt(v, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.NewRequestFailure(awserr.New(request.ParamFormatErrCode,
|
||||||
|
"unable to parse EC2 token TTL response", err), r.HTTPResponse.StatusCode, r.RequestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := time.Duration(i) * time.Second
|
||||||
|
data.TTL = t
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var unmarshalHandler = request.NamedHandler{
|
||||||
|
Name: unmarshalMetadataHandlerName,
|
||||||
|
Fn: func(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
var b bytes.Buffer
|
||||||
|
if _, err := io.Copy(&b, r.HTTPResponse.Body); err != nil {
|
||||||
|
r.Error = awserr.NewRequestFailure(awserr.New(request.ErrCodeSerialization,
|
||||||
|
"unable to unmarshal EC2 metadata response", err), r.HTTPResponse.StatusCode, r.RequestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if data, ok := r.Data.(*metadataOutput); ok {
|
||||||
|
data.Content = b.String()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalError(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
var b bytes.Buffer
|
||||||
|
|
||||||
|
if _, err := io.Copy(&b, r.HTTPResponse.Body); err != nil {
|
||||||
|
r.Error = awserr.NewRequestFailure(
|
||||||
|
awserr.New(request.ErrCodeSerialization, "unable to unmarshal EC2 metadata error response", err),
|
||||||
|
r.HTTPResponse.StatusCode, r.RequestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response body format is not consistent between metadata endpoints.
|
||||||
|
// Grab the error message as a string and include that as the source error
|
||||||
|
r.Error = awserr.NewRequestFailure(
|
||||||
|
awserr.New("EC2MetadataError", "failed to make EC2Metadata request\n"+b.String(), nil),
|
||||||
|
r.HTTPResponse.StatusCode, r.RequestID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateEndpointHandler(r *request.Request) {
|
||||||
|
if r.ClientInfo.Endpoint == "" {
|
||||||
|
r.Error = aws.ErrMissingEndpoint
|
||||||
|
}
|
||||||
|
}
|
93
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/token_provider.go
generated
vendored
Normal file
93
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/token_provider.go
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package ec2metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A tokenProvider struct provides access to EC2Metadata client
|
||||||
|
// and atomic instance of a token, along with configuredTTL for it.
|
||||||
|
// tokenProvider also provides an atomic flag to disable the
|
||||||
|
// fetch token operation.
|
||||||
|
// The disabled member will use 0 as false, and 1 as true.
|
||||||
|
type tokenProvider struct {
|
||||||
|
client *EC2Metadata
|
||||||
|
token atomic.Value
|
||||||
|
configuredTTL time.Duration
|
||||||
|
disabled uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// A ec2Token struct helps use of token in EC2 Metadata service ops
|
||||||
|
type ec2Token struct {
|
||||||
|
token string
|
||||||
|
credentials.Expiry
|
||||||
|
}
|
||||||
|
|
||||||
|
// newTokenProvider provides a pointer to a tokenProvider instance
|
||||||
|
func newTokenProvider(c *EC2Metadata, duration time.Duration) *tokenProvider {
|
||||||
|
return &tokenProvider{client: c, configuredTTL: duration}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchTokenHandler fetches token for EC2Metadata service client by default.
|
||||||
|
func (t *tokenProvider) fetchTokenHandler(r *request.Request) {
|
||||||
|
|
||||||
|
// short-circuits to insecure data flow if tokenProvider is disabled.
|
||||||
|
if v := atomic.LoadUint32(&t.disabled); v == 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ec2Token, ok := t.token.Load().(ec2Token); ok && !ec2Token.IsExpired() {
|
||||||
|
r.HTTPRequest.Header.Set(tokenHeader, ec2Token.token)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := t.client.getToken(r.Context(), t.configuredTTL)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
// change the disabled flag on token provider to true,
|
||||||
|
// when error is request timeout error.
|
||||||
|
if requestFailureError, ok := err.(awserr.RequestFailure); ok {
|
||||||
|
switch requestFailureError.StatusCode() {
|
||||||
|
case http.StatusForbidden, http.StatusNotFound, http.StatusMethodNotAllowed:
|
||||||
|
atomic.StoreUint32(&t.disabled, 1)
|
||||||
|
case http.StatusBadRequest:
|
||||||
|
r.Error = requestFailureError
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if request timed out while waiting for response
|
||||||
|
if e, ok := requestFailureError.OrigErr().(awserr.Error); ok {
|
||||||
|
if e.Code() == request.ErrCodeRequestError {
|
||||||
|
atomic.StoreUint32(&t.disabled, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newToken := ec2Token{
|
||||||
|
token: output.Token,
|
||||||
|
}
|
||||||
|
newToken.SetExpiration(time.Now().Add(output.TTL), ttlExpirationWindow)
|
||||||
|
t.token.Store(newToken)
|
||||||
|
|
||||||
|
// Inject token header to the request.
|
||||||
|
if ec2Token, ok := t.token.Load().(ec2Token); ok {
|
||||||
|
r.HTTPRequest.Header.Set(tokenHeader, ec2Token.token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// enableTokenProviderHandler enables the token provider
|
||||||
|
func (t *tokenProvider) enableTokenProviderHandler(r *request.Request) {
|
||||||
|
// If the error code status is 401, we enable the token provider
|
||||||
|
if e, ok := r.Error.(awserr.RequestFailure); ok && e != nil &&
|
||||||
|
e.StatusCode() == http.StatusUnauthorized {
|
||||||
|
t.token.Store(ec2Token{})
|
||||||
|
atomic.StoreUint32(&t.disabled, 0)
|
||||||
|
}
|
||||||
|
}
|
193
vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode.go
generated
vendored
Normal file
193
vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode.go
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type modelDefinition map[string]json.RawMessage
|
||||||
|
|
||||||
|
// A DecodeModelOptions are the options for how the endpoints model definition
|
||||||
|
// are decoded.
|
||||||
|
type DecodeModelOptions struct {
|
||||||
|
SkipCustomizations bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set combines all of the option functions together.
|
||||||
|
func (d *DecodeModelOptions) Set(optFns ...func(*DecodeModelOptions)) {
|
||||||
|
for _, fn := range optFns {
|
||||||
|
fn(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeModel unmarshals a Regions and Endpoint model definition file into
|
||||||
|
// a endpoint Resolver. If the file format is not supported, or an error occurs
|
||||||
|
// when unmarshaling the model an error will be returned.
|
||||||
|
//
|
||||||
|
// Casting the return value of this func to a EnumPartitions will
|
||||||
|
// allow you to get a list of the partitions in the order the endpoints
|
||||||
|
// will be resolved in.
|
||||||
|
//
|
||||||
|
// resolver, err := endpoints.DecodeModel(reader)
|
||||||
|
//
|
||||||
|
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
|
||||||
|
// for _, p := range partitions {
|
||||||
|
// // ... inspect partitions
|
||||||
|
// }
|
||||||
|
func DecodeModel(r io.Reader, optFns ...func(*DecodeModelOptions)) (Resolver, error) {
|
||||||
|
var opts DecodeModelOptions
|
||||||
|
opts.Set(optFns...)
|
||||||
|
|
||||||
|
// Get the version of the partition file to determine what
|
||||||
|
// unmarshaling model to use.
|
||||||
|
modelDef := modelDefinition{}
|
||||||
|
if err := json.NewDecoder(r).Decode(&modelDef); err != nil {
|
||||||
|
return nil, newDecodeModelError("failed to decode endpoints model", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var version string
|
||||||
|
if b, ok := modelDef["version"]; ok {
|
||||||
|
version = string(b)
|
||||||
|
} else {
|
||||||
|
return nil, newDecodeModelError("endpoints version not found in model", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if version == "3" {
|
||||||
|
return decodeV3Endpoints(modelDef, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, newDecodeModelError(
|
||||||
|
fmt.Sprintf("endpoints version %s, not supported", version), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resolver, error) {
|
||||||
|
b, ok := modelDef["partitions"]
|
||||||
|
if !ok {
|
||||||
|
return nil, newDecodeModelError("endpoints model missing partitions", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
ps := partitions{}
|
||||||
|
if err := json.Unmarshal(b, &ps); err != nil {
|
||||||
|
return nil, newDecodeModelError("failed to decode endpoints model", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.SkipCustomizations {
|
||||||
|
return ps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Customization
|
||||||
|
for i := 0; i < len(ps); i++ {
|
||||||
|
p := &ps[i]
|
||||||
|
custRegionalS3(p)
|
||||||
|
custRmIotDataService(p)
|
||||||
|
custFixAppAutoscalingChina(p)
|
||||||
|
custFixAppAutoscalingUsGov(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func custRegionalS3(p *partition) {
|
||||||
|
if p.ID != "aws" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
service, ok := p.Services["s3"]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const awsGlobal = "aws-global"
|
||||||
|
const usEast1 = "us-east-1"
|
||||||
|
|
||||||
|
// If global endpoint already exists no customization needed.
|
||||||
|
if _, ok := service.Endpoints[endpointKey{Region: awsGlobal}]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
service.PartitionEndpoint = awsGlobal
|
||||||
|
if _, ok := service.Endpoints[endpointKey{Region: usEast1}]; !ok {
|
||||||
|
service.Endpoints[endpointKey{Region: usEast1}] = endpoint{}
|
||||||
|
}
|
||||||
|
service.Endpoints[endpointKey{Region: awsGlobal}] = endpoint{
|
||||||
|
Hostname: "s3.amazonaws.com",
|
||||||
|
CredentialScope: credentialScope{
|
||||||
|
Region: usEast1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Services["s3"] = service
|
||||||
|
}
|
||||||
|
|
||||||
|
func custRmIotDataService(p *partition) {
|
||||||
|
delete(p.Services, "data.iot")
|
||||||
|
}
|
||||||
|
|
||||||
|
func custFixAppAutoscalingChina(p *partition) {
|
||||||
|
if p.ID != "aws-cn" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceName = "application-autoscaling"
|
||||||
|
s, ok := p.Services[serviceName]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectHostname = `autoscaling.{region}.amazonaws.com`
|
||||||
|
serviceDefault := s.Defaults[defaultKey{}]
|
||||||
|
if e, a := expectHostname, serviceDefault.Hostname; e != a {
|
||||||
|
fmt.Printf("custFixAppAutoscalingChina: ignoring customization, expected %s, got %s\n", e, a)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
serviceDefault.Hostname = expectHostname + ".cn"
|
||||||
|
s.Defaults[defaultKey{}] = serviceDefault
|
||||||
|
p.Services[serviceName] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func custFixAppAutoscalingUsGov(p *partition) {
|
||||||
|
if p.ID != "aws-us-gov" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceName = "application-autoscaling"
|
||||||
|
s, ok := p.Services[serviceName]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceDefault := s.Defaults[defaultKey{}]
|
||||||
|
if a := serviceDefault.CredentialScope.Service; a != "" {
|
||||||
|
fmt.Printf("custFixAppAutoscalingUsGov: ignoring customization, expected empty credential scope service, got %s\n", a)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if a := serviceDefault.Hostname; a != "" {
|
||||||
|
fmt.Printf("custFixAppAutoscalingUsGov: ignoring customization, expected empty hostname, got %s\n", a)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceDefault.CredentialScope.Service = "application-autoscaling"
|
||||||
|
serviceDefault.Hostname = "autoscaling.{region}.amazonaws.com"
|
||||||
|
|
||||||
|
if s.Defaults == nil {
|
||||||
|
s.Defaults = make(endpointDefaults)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Defaults[defaultKey{}] = serviceDefault
|
||||||
|
|
||||||
|
p.Services[serviceName] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
type decodeModelError struct {
|
||||||
|
awsError
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDecodeModelError(msg string, err error) decodeModelError {
|
||||||
|
return decodeModelError{
|
||||||
|
awsError: awserr.New("DecodeEndpointsModelError", msg, err),
|
||||||
|
}
|
||||||
|
}
|
33723
vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
generated
vendored
Normal file
33723
vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
141
vendor/github.com/aws/aws-sdk-go/aws/endpoints/dep_service_ids.go
generated
vendored
Normal file
141
vendor/github.com/aws/aws-sdk-go/aws/endpoints/dep_service_ids.go
generated
vendored
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package endpoints
|
||||||
|
|
||||||
|
// Service identifiers
|
||||||
|
//
|
||||||
|
// Deprecated: Use client package's EndpointsID value instead of these
|
||||||
|
// ServiceIDs. These IDs are not maintained, and are out of date.
|
||||||
|
const (
|
||||||
|
A4bServiceID = "a4b" // A4b.
|
||||||
|
AcmServiceID = "acm" // Acm.
|
||||||
|
AcmPcaServiceID = "acm-pca" // AcmPca.
|
||||||
|
ApiMediatailorServiceID = "api.mediatailor" // ApiMediatailor.
|
||||||
|
ApiPricingServiceID = "api.pricing" // ApiPricing.
|
||||||
|
ApiSagemakerServiceID = "api.sagemaker" // ApiSagemaker.
|
||||||
|
ApigatewayServiceID = "apigateway" // Apigateway.
|
||||||
|
ApplicationAutoscalingServiceID = "application-autoscaling" // ApplicationAutoscaling.
|
||||||
|
Appstream2ServiceID = "appstream2" // Appstream2.
|
||||||
|
AppsyncServiceID = "appsync" // Appsync.
|
||||||
|
AthenaServiceID = "athena" // Athena.
|
||||||
|
AutoscalingServiceID = "autoscaling" // Autoscaling.
|
||||||
|
AutoscalingPlansServiceID = "autoscaling-plans" // AutoscalingPlans.
|
||||||
|
BatchServiceID = "batch" // Batch.
|
||||||
|
BudgetsServiceID = "budgets" // Budgets.
|
||||||
|
CeServiceID = "ce" // Ce.
|
||||||
|
ChimeServiceID = "chime" // Chime.
|
||||||
|
Cloud9ServiceID = "cloud9" // Cloud9.
|
||||||
|
ClouddirectoryServiceID = "clouddirectory" // Clouddirectory.
|
||||||
|
CloudformationServiceID = "cloudformation" // Cloudformation.
|
||||||
|
CloudfrontServiceID = "cloudfront" // Cloudfront.
|
||||||
|
CloudhsmServiceID = "cloudhsm" // Cloudhsm.
|
||||||
|
Cloudhsmv2ServiceID = "cloudhsmv2" // Cloudhsmv2.
|
||||||
|
CloudsearchServiceID = "cloudsearch" // Cloudsearch.
|
||||||
|
CloudtrailServiceID = "cloudtrail" // Cloudtrail.
|
||||||
|
CodebuildServiceID = "codebuild" // Codebuild.
|
||||||
|
CodecommitServiceID = "codecommit" // Codecommit.
|
||||||
|
CodedeployServiceID = "codedeploy" // Codedeploy.
|
||||||
|
CodepipelineServiceID = "codepipeline" // Codepipeline.
|
||||||
|
CodestarServiceID = "codestar" // Codestar.
|
||||||
|
CognitoIdentityServiceID = "cognito-identity" // CognitoIdentity.
|
||||||
|
CognitoIdpServiceID = "cognito-idp" // CognitoIdp.
|
||||||
|
CognitoSyncServiceID = "cognito-sync" // CognitoSync.
|
||||||
|
ComprehendServiceID = "comprehend" // Comprehend.
|
||||||
|
ConfigServiceID = "config" // Config.
|
||||||
|
CurServiceID = "cur" // Cur.
|
||||||
|
DatapipelineServiceID = "datapipeline" // Datapipeline.
|
||||||
|
DaxServiceID = "dax" // Dax.
|
||||||
|
DevicefarmServiceID = "devicefarm" // Devicefarm.
|
||||||
|
DirectconnectServiceID = "directconnect" // Directconnect.
|
||||||
|
DiscoveryServiceID = "discovery" // Discovery.
|
||||||
|
DmsServiceID = "dms" // Dms.
|
||||||
|
DsServiceID = "ds" // Ds.
|
||||||
|
DynamodbServiceID = "dynamodb" // Dynamodb.
|
||||||
|
Ec2ServiceID = "ec2" // Ec2.
|
||||||
|
Ec2metadataServiceID = "ec2metadata" // Ec2metadata.
|
||||||
|
EcrServiceID = "ecr" // Ecr.
|
||||||
|
EcsServiceID = "ecs" // Ecs.
|
||||||
|
ElasticacheServiceID = "elasticache" // Elasticache.
|
||||||
|
ElasticbeanstalkServiceID = "elasticbeanstalk" // Elasticbeanstalk.
|
||||||
|
ElasticfilesystemServiceID = "elasticfilesystem" // Elasticfilesystem.
|
||||||
|
ElasticloadbalancingServiceID = "elasticloadbalancing" // Elasticloadbalancing.
|
||||||
|
ElasticmapreduceServiceID = "elasticmapreduce" // Elasticmapreduce.
|
||||||
|
ElastictranscoderServiceID = "elastictranscoder" // Elastictranscoder.
|
||||||
|
EmailServiceID = "email" // Email.
|
||||||
|
EntitlementMarketplaceServiceID = "entitlement.marketplace" // EntitlementMarketplace.
|
||||||
|
EsServiceID = "es" // Es.
|
||||||
|
EventsServiceID = "events" // Events.
|
||||||
|
FirehoseServiceID = "firehose" // Firehose.
|
||||||
|
FmsServiceID = "fms" // Fms.
|
||||||
|
GameliftServiceID = "gamelift" // Gamelift.
|
||||||
|
GlacierServiceID = "glacier" // Glacier.
|
||||||
|
GlueServiceID = "glue" // Glue.
|
||||||
|
GreengrassServiceID = "greengrass" // Greengrass.
|
||||||
|
GuarddutyServiceID = "guardduty" // Guardduty.
|
||||||
|
HealthServiceID = "health" // Health.
|
||||||
|
IamServiceID = "iam" // Iam.
|
||||||
|
ImportexportServiceID = "importexport" // Importexport.
|
||||||
|
InspectorServiceID = "inspector" // Inspector.
|
||||||
|
IotServiceID = "iot" // Iot.
|
||||||
|
IotanalyticsServiceID = "iotanalytics" // Iotanalytics.
|
||||||
|
KinesisServiceID = "kinesis" // Kinesis.
|
||||||
|
KinesisanalyticsServiceID = "kinesisanalytics" // Kinesisanalytics.
|
||||||
|
KinesisvideoServiceID = "kinesisvideo" // Kinesisvideo.
|
||||||
|
KmsServiceID = "kms" // Kms.
|
||||||
|
LambdaServiceID = "lambda" // Lambda.
|
||||||
|
LightsailServiceID = "lightsail" // Lightsail.
|
||||||
|
LogsServiceID = "logs" // Logs.
|
||||||
|
MachinelearningServiceID = "machinelearning" // Machinelearning.
|
||||||
|
MarketplacecommerceanalyticsServiceID = "marketplacecommerceanalytics" // Marketplacecommerceanalytics.
|
||||||
|
MediaconvertServiceID = "mediaconvert" // Mediaconvert.
|
||||||
|
MedialiveServiceID = "medialive" // Medialive.
|
||||||
|
MediapackageServiceID = "mediapackage" // Mediapackage.
|
||||||
|
MediastoreServiceID = "mediastore" // Mediastore.
|
||||||
|
MeteringMarketplaceServiceID = "metering.marketplace" // MeteringMarketplace.
|
||||||
|
MghServiceID = "mgh" // Mgh.
|
||||||
|
MobileanalyticsServiceID = "mobileanalytics" // Mobileanalytics.
|
||||||
|
ModelsLexServiceID = "models.lex" // ModelsLex.
|
||||||
|
MonitoringServiceID = "monitoring" // Monitoring.
|
||||||
|
MturkRequesterServiceID = "mturk-requester" // MturkRequester.
|
||||||
|
NeptuneServiceID = "neptune" // Neptune.
|
||||||
|
OpsworksServiceID = "opsworks" // Opsworks.
|
||||||
|
OpsworksCmServiceID = "opsworks-cm" // OpsworksCm.
|
||||||
|
OrganizationsServiceID = "organizations" // Organizations.
|
||||||
|
PinpointServiceID = "pinpoint" // Pinpoint.
|
||||||
|
PollyServiceID = "polly" // Polly.
|
||||||
|
RdsServiceID = "rds" // Rds.
|
||||||
|
RedshiftServiceID = "redshift" // Redshift.
|
||||||
|
RekognitionServiceID = "rekognition" // Rekognition.
|
||||||
|
ResourceGroupsServiceID = "resource-groups" // ResourceGroups.
|
||||||
|
Route53ServiceID = "route53" // Route53.
|
||||||
|
Route53domainsServiceID = "route53domains" // Route53domains.
|
||||||
|
RuntimeLexServiceID = "runtime.lex" // RuntimeLex.
|
||||||
|
RuntimeSagemakerServiceID = "runtime.sagemaker" // RuntimeSagemaker.
|
||||||
|
S3ServiceID = "s3" // S3.
|
||||||
|
S3ControlServiceID = "s3-control" // S3Control.
|
||||||
|
SagemakerServiceID = "api.sagemaker" // Sagemaker.
|
||||||
|
SdbServiceID = "sdb" // Sdb.
|
||||||
|
SecretsmanagerServiceID = "secretsmanager" // Secretsmanager.
|
||||||
|
ServerlessrepoServiceID = "serverlessrepo" // Serverlessrepo.
|
||||||
|
ServicecatalogServiceID = "servicecatalog" // Servicecatalog.
|
||||||
|
ServicediscoveryServiceID = "servicediscovery" // Servicediscovery.
|
||||||
|
ShieldServiceID = "shield" // Shield.
|
||||||
|
SmsServiceID = "sms" // Sms.
|
||||||
|
SnowballServiceID = "snowball" // Snowball.
|
||||||
|
SnsServiceID = "sns" // Sns.
|
||||||
|
SqsServiceID = "sqs" // Sqs.
|
||||||
|
SsmServiceID = "ssm" // Ssm.
|
||||||
|
StatesServiceID = "states" // States.
|
||||||
|
StoragegatewayServiceID = "storagegateway" // Storagegateway.
|
||||||
|
StreamsDynamodbServiceID = "streams.dynamodb" // StreamsDynamodb.
|
||||||
|
StsServiceID = "sts" // Sts.
|
||||||
|
SupportServiceID = "support" // Support.
|
||||||
|
SwfServiceID = "swf" // Swf.
|
||||||
|
TaggingServiceID = "tagging" // Tagging.
|
||||||
|
TransferServiceID = "transfer" // Transfer.
|
||||||
|
TranslateServiceID = "translate" // Translate.
|
||||||
|
WafServiceID = "waf" // Waf.
|
||||||
|
WafRegionalServiceID = "waf-regional" // WafRegional.
|
||||||
|
WorkdocsServiceID = "workdocs" // Workdocs.
|
||||||
|
WorkmailServiceID = "workmail" // Workmail.
|
||||||
|
WorkspacesServiceID = "workspaces" // Workspaces.
|
||||||
|
XrayServiceID = "xray" // Xray.
|
||||||
|
)
|
65
vendor/github.com/aws/aws-sdk-go/aws/endpoints/doc.go
generated
vendored
Normal file
65
vendor/github.com/aws/aws-sdk-go/aws/endpoints/doc.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Package endpoints provides the types and functionality for defining regions
|
||||||
|
// and endpoints, as well as querying those definitions.
|
||||||
|
//
|
||||||
|
// The SDK's Regions and Endpoints metadata is code generated into the endpoints
|
||||||
|
// package, and is accessible via the DefaultResolver function. This function
|
||||||
|
// returns a endpoint Resolver will search the metadata and build an associated
|
||||||
|
// endpoint if one is found. The default resolver will search all partitions
|
||||||
|
// known by the SDK. e.g AWS Standard (aws), AWS China (aws-cn), and
|
||||||
|
// AWS GovCloud (US) (aws-us-gov).
|
||||||
|
// .
|
||||||
|
//
|
||||||
|
// # Enumerating Regions and Endpoint Metadata
|
||||||
|
//
|
||||||
|
// Casting the Resolver returned by DefaultResolver to a EnumPartitions interface
|
||||||
|
// will allow you to get access to the list of underlying Partitions with the
|
||||||
|
// Partitions method. This is helpful if you want to limit the SDK's endpoint
|
||||||
|
// resolving to a single partition, or enumerate regions, services, and endpoints
|
||||||
|
// in the partition.
|
||||||
|
//
|
||||||
|
// resolver := endpoints.DefaultResolver()
|
||||||
|
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
|
||||||
|
//
|
||||||
|
// for _, p := range partitions {
|
||||||
|
// fmt.Println("Regions for", p.ID())
|
||||||
|
// for id, _ := range p.Regions() {
|
||||||
|
// fmt.Println("*", id)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fmt.Println("Services for", p.ID())
|
||||||
|
// for id, _ := range p.Services() {
|
||||||
|
// fmt.Println("*", id)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// # Using Custom Endpoints
|
||||||
|
//
|
||||||
|
// The endpoints package also gives you the ability to use your own logic how
|
||||||
|
// endpoints are resolved. This is a great way to define a custom endpoint
|
||||||
|
// for select services, without passing that logic down through your code.
|
||||||
|
//
|
||||||
|
// If a type implements the Resolver interface it can be used to resolve
|
||||||
|
// endpoints. To use this with the SDK's Session and Config set the value
|
||||||
|
// of the type to the EndpointsResolver field of aws.Config when initializing
|
||||||
|
// the session, or service client.
|
||||||
|
//
|
||||||
|
// In addition the ResolverFunc is a wrapper for a func matching the signature
|
||||||
|
// of Resolver.EndpointFor, converting it to a type that satisfies the
|
||||||
|
// Resolver interface.
|
||||||
|
//
|
||||||
|
// myCustomResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
|
||||||
|
// if service == endpoints.S3ServiceID {
|
||||||
|
// return endpoints.ResolvedEndpoint{
|
||||||
|
// URL: "s3.custom.endpoint.com",
|
||||||
|
// SigningRegion: "custom-signing-region",
|
||||||
|
// }, nil
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return endpoints.DefaultResolver().EndpointFor(service, region, optFns...)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// sess := session.Must(session.NewSession(&aws.Config{
|
||||||
|
// Region: aws.String("us-west-2"),
|
||||||
|
// EndpointResolver: endpoints.ResolverFunc(myCustomResolver),
|
||||||
|
// }))
|
||||||
|
package endpoints
|
708
vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints.go
generated
vendored
Normal file
708
vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints.go
generated
vendored
Normal file
@ -0,0 +1,708 @@
|
|||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Logger is a minimalistic interface for the SDK to log messages to.
|
||||||
|
type Logger interface {
|
||||||
|
Log(...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// DualStackEndpointState is a constant to describe the dual-stack endpoint resolution
|
||||||
|
// behavior.
|
||||||
|
type DualStackEndpointState uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DualStackEndpointStateUnset is the default value behavior for dual-stack endpoint
|
||||||
|
// resolution.
|
||||||
|
DualStackEndpointStateUnset DualStackEndpointState = iota
|
||||||
|
|
||||||
|
// DualStackEndpointStateEnabled enable dual-stack endpoint resolution for endpoints.
|
||||||
|
DualStackEndpointStateEnabled
|
||||||
|
|
||||||
|
// DualStackEndpointStateDisabled disables dual-stack endpoint resolution for endpoints.
|
||||||
|
DualStackEndpointStateDisabled
|
||||||
|
)
|
||||||
|
|
||||||
|
// FIPSEndpointState is a constant to describe the FIPS endpoint resolution behavior.
|
||||||
|
type FIPSEndpointState uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
// FIPSEndpointStateUnset is the default value behavior for FIPS endpoint resolution.
|
||||||
|
FIPSEndpointStateUnset FIPSEndpointState = iota
|
||||||
|
|
||||||
|
// FIPSEndpointStateEnabled enables FIPS endpoint resolution for service endpoints.
|
||||||
|
FIPSEndpointStateEnabled
|
||||||
|
|
||||||
|
// FIPSEndpointStateDisabled disables FIPS endpoint resolution for endpoints.
|
||||||
|
FIPSEndpointStateDisabled
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options provide the configuration needed to direct how the
|
||||||
|
// endpoints will be resolved.
|
||||||
|
type Options struct {
|
||||||
|
// DisableSSL forces the endpoint to be resolved as HTTP.
|
||||||
|
// instead of HTTPS if the service supports it.
|
||||||
|
DisableSSL bool
|
||||||
|
|
||||||
|
// Sets the resolver to resolve the endpoint as a dualstack endpoint
|
||||||
|
// for the service. If dualstack support for a service is not known and
|
||||||
|
// StrictMatching is not enabled a dualstack endpoint for the service will
|
||||||
|
// be returned. This endpoint may not be valid. If StrictMatching is
|
||||||
|
// enabled only services that are known to support dualstack will return
|
||||||
|
// dualstack endpoints.
|
||||||
|
//
|
||||||
|
// Deprecated: This option will continue to function for S3 and S3 Control for backwards compatibility.
|
||||||
|
// UseDualStackEndpoint should be used to enable usage of a service's dual-stack endpoint for all service clients
|
||||||
|
// moving forward. For S3 and S3 Control, when UseDualStackEndpoint is set to a non-zero value it takes higher
|
||||||
|
// precedence then this option.
|
||||||
|
UseDualStack bool
|
||||||
|
|
||||||
|
// Sets the resolver to resolve a dual-stack endpoint for the service.
|
||||||
|
UseDualStackEndpoint DualStackEndpointState
|
||||||
|
|
||||||
|
// UseFIPSEndpoint specifies the resolver must resolve a FIPS endpoint.
|
||||||
|
UseFIPSEndpoint FIPSEndpointState
|
||||||
|
|
||||||
|
// Enables strict matching of services and regions resolved endpoints.
|
||||||
|
// If the partition doesn't enumerate the exact service and region an
|
||||||
|
// error will be returned. This option will prevent returning endpoints
|
||||||
|
// that look valid, but may not resolve to any real endpoint.
|
||||||
|
StrictMatching bool
|
||||||
|
|
||||||
|
// Enables resolving a service endpoint based on the region provided if the
|
||||||
|
// service does not exist. The service endpoint ID will be used as the service
|
||||||
|
// domain name prefix. By default the endpoint resolver requires the service
|
||||||
|
// to be known when resolving endpoints.
|
||||||
|
//
|
||||||
|
// If resolving an endpoint on the partition list the provided region will
|
||||||
|
// be used to determine which partition's domain name pattern to the service
|
||||||
|
// endpoint ID with. If both the service and region are unknown and resolving
|
||||||
|
// the endpoint on partition list an UnknownEndpointError error will be returned.
|
||||||
|
//
|
||||||
|
// If resolving and endpoint on a partition specific resolver that partition's
|
||||||
|
// domain name pattern will be used with the service endpoint ID. If both
|
||||||
|
// region and service do not exist when resolving an endpoint on a specific
|
||||||
|
// partition the partition's domain pattern will be used to combine the
|
||||||
|
// endpoint and region together.
|
||||||
|
//
|
||||||
|
// This option is ignored if StrictMatching is enabled.
|
||||||
|
ResolveUnknownService bool
|
||||||
|
|
||||||
|
// Specifies the EC2 Instance Metadata Service default endpoint selection mode (IPv4 or IPv6)
|
||||||
|
EC2MetadataEndpointMode EC2IMDSEndpointModeState
|
||||||
|
|
||||||
|
// STS Regional Endpoint flag helps with resolving the STS endpoint
|
||||||
|
STSRegionalEndpoint STSRegionalEndpoint
|
||||||
|
|
||||||
|
// S3 Regional Endpoint flag helps with resolving the S3 endpoint
|
||||||
|
S3UsEast1RegionalEndpoint S3UsEast1RegionalEndpoint
|
||||||
|
|
||||||
|
// ResolvedRegion is the resolved region string. If provided (non-zero length) it takes priority
|
||||||
|
// over the region name passed to the ResolveEndpoint call.
|
||||||
|
ResolvedRegion string
|
||||||
|
|
||||||
|
// Logger is the logger that will be used to log messages.
|
||||||
|
Logger Logger
|
||||||
|
|
||||||
|
// Determines whether logging of deprecated endpoints usage is enabled.
|
||||||
|
LogDeprecated bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Options) getEndpointVariant(service string) (v endpointVariant) {
|
||||||
|
const s3 = "s3"
|
||||||
|
const s3Control = "s3-control"
|
||||||
|
|
||||||
|
if (o.UseDualStackEndpoint == DualStackEndpointStateEnabled) ||
|
||||||
|
((service == s3 || service == s3Control) && (o.UseDualStackEndpoint == DualStackEndpointStateUnset && o.UseDualStack)) {
|
||||||
|
v |= dualStackVariant
|
||||||
|
}
|
||||||
|
if o.UseFIPSEndpoint == FIPSEndpointStateEnabled {
|
||||||
|
v |= fipsVariant
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// EC2IMDSEndpointModeState is an enum configuration variable describing the client endpoint mode.
|
||||||
|
type EC2IMDSEndpointModeState uint
|
||||||
|
|
||||||
|
// Enumeration values for EC2IMDSEndpointModeState
|
||||||
|
const (
|
||||||
|
EC2IMDSEndpointModeStateUnset EC2IMDSEndpointModeState = iota
|
||||||
|
EC2IMDSEndpointModeStateIPv4
|
||||||
|
EC2IMDSEndpointModeStateIPv6
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetFromString sets the EC2IMDSEndpointModeState based on the provided string value. Unknown values will default to EC2IMDSEndpointModeStateUnset
|
||||||
|
func (e *EC2IMDSEndpointModeState) SetFromString(v string) error {
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(v) == 0:
|
||||||
|
*e = EC2IMDSEndpointModeStateUnset
|
||||||
|
case strings.EqualFold(v, "IPv6"):
|
||||||
|
*e = EC2IMDSEndpointModeStateIPv6
|
||||||
|
case strings.EqualFold(v, "IPv4"):
|
||||||
|
*e = EC2IMDSEndpointModeStateIPv4
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown EC2 IMDS endpoint mode, must be either IPv6 or IPv4")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// STSRegionalEndpoint is an enum for the states of the STS Regional Endpoint
|
||||||
|
// options.
|
||||||
|
type STSRegionalEndpoint int
|
||||||
|
|
||||||
|
func (e STSRegionalEndpoint) String() string {
|
||||||
|
switch e {
|
||||||
|
case LegacySTSEndpoint:
|
||||||
|
return "legacy"
|
||||||
|
case RegionalSTSEndpoint:
|
||||||
|
return "regional"
|
||||||
|
case UnsetSTSEndpoint:
|
||||||
|
return ""
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// UnsetSTSEndpoint represents that STS Regional Endpoint flag is not specified.
|
||||||
|
UnsetSTSEndpoint STSRegionalEndpoint = iota
|
||||||
|
|
||||||
|
// LegacySTSEndpoint represents when STS Regional Endpoint flag is specified
|
||||||
|
// to use legacy endpoints.
|
||||||
|
LegacySTSEndpoint
|
||||||
|
|
||||||
|
// RegionalSTSEndpoint represents when STS Regional Endpoint flag is specified
|
||||||
|
// to use regional endpoints.
|
||||||
|
RegionalSTSEndpoint
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetSTSRegionalEndpoint function returns the STSRegionalEndpointFlag based
|
||||||
|
// on the input string provided in env config or shared config by the user.
|
||||||
|
//
|
||||||
|
// `legacy`, `regional` are the only case-insensitive valid strings for
|
||||||
|
// resolving the STS regional Endpoint flag.
|
||||||
|
func GetSTSRegionalEndpoint(s string) (STSRegionalEndpoint, error) {
|
||||||
|
switch {
|
||||||
|
case strings.EqualFold(s, "legacy"):
|
||||||
|
return LegacySTSEndpoint, nil
|
||||||
|
case strings.EqualFold(s, "regional"):
|
||||||
|
return RegionalSTSEndpoint, nil
|
||||||
|
default:
|
||||||
|
return UnsetSTSEndpoint, fmt.Errorf("unable to resolve the value of STSRegionalEndpoint for %v", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// S3UsEast1RegionalEndpoint is an enum for the states of the S3 us-east-1
|
||||||
|
// Regional Endpoint options.
|
||||||
|
type S3UsEast1RegionalEndpoint int
|
||||||
|
|
||||||
|
func (e S3UsEast1RegionalEndpoint) String() string {
|
||||||
|
switch e {
|
||||||
|
case LegacyS3UsEast1Endpoint:
|
||||||
|
return "legacy"
|
||||||
|
case RegionalS3UsEast1Endpoint:
|
||||||
|
return "regional"
|
||||||
|
case UnsetS3UsEast1Endpoint:
|
||||||
|
return ""
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// UnsetS3UsEast1Endpoint represents that S3 Regional Endpoint flag is not
|
||||||
|
// specified.
|
||||||
|
UnsetS3UsEast1Endpoint S3UsEast1RegionalEndpoint = iota
|
||||||
|
|
||||||
|
// LegacyS3UsEast1Endpoint represents when S3 Regional Endpoint flag is
|
||||||
|
// specified to use legacy endpoints.
|
||||||
|
LegacyS3UsEast1Endpoint
|
||||||
|
|
||||||
|
// RegionalS3UsEast1Endpoint represents when S3 Regional Endpoint flag is
|
||||||
|
// specified to use regional endpoints.
|
||||||
|
RegionalS3UsEast1Endpoint
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetS3UsEast1RegionalEndpoint function returns the S3UsEast1RegionalEndpointFlag based
|
||||||
|
// on the input string provided in env config or shared config by the user.
|
||||||
|
//
|
||||||
|
// `legacy`, `regional` are the only case-insensitive valid strings for
|
||||||
|
// resolving the S3 regional Endpoint flag.
|
||||||
|
func GetS3UsEast1RegionalEndpoint(s string) (S3UsEast1RegionalEndpoint, error) {
|
||||||
|
switch {
|
||||||
|
case strings.EqualFold(s, "legacy"):
|
||||||
|
return LegacyS3UsEast1Endpoint, nil
|
||||||
|
case strings.EqualFold(s, "regional"):
|
||||||
|
return RegionalS3UsEast1Endpoint, nil
|
||||||
|
default:
|
||||||
|
return UnsetS3UsEast1Endpoint,
|
||||||
|
fmt.Errorf("unable to resolve the value of S3UsEast1RegionalEndpoint for %v", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set combines all of the option functions together.
|
||||||
|
func (o *Options) Set(optFns ...func(*Options)) {
|
||||||
|
for _, fn := range optFns {
|
||||||
|
fn(o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableSSLOption sets the DisableSSL options. Can be used as a functional
|
||||||
|
// option when resolving endpoints.
|
||||||
|
func DisableSSLOption(o *Options) {
|
||||||
|
o.DisableSSL = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// UseDualStackOption sets the UseDualStack option. Can be used as a functional
|
||||||
|
// option when resolving endpoints.
|
||||||
|
//
|
||||||
|
// Deprecated: UseDualStackEndpointOption should be used to enable usage of a service's dual-stack endpoint.
|
||||||
|
// When DualStackEndpointState is set to a non-zero value it takes higher precedence then this option.
|
||||||
|
func UseDualStackOption(o *Options) {
|
||||||
|
o.UseDualStack = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// UseDualStackEndpointOption sets the UseDualStackEndpoint option to enabled. Can be used as a functional
|
||||||
|
// option when resolving endpoints.
|
||||||
|
func UseDualStackEndpointOption(o *Options) {
|
||||||
|
o.UseDualStackEndpoint = DualStackEndpointStateEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// UseFIPSEndpointOption sets the UseFIPSEndpoint option to enabled. Can be used as a functional
|
||||||
|
// option when resolving endpoints.
|
||||||
|
func UseFIPSEndpointOption(o *Options) {
|
||||||
|
o.UseFIPSEndpoint = FIPSEndpointStateEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrictMatchingOption sets the StrictMatching option. Can be used as a functional
|
||||||
|
// option when resolving endpoints.
|
||||||
|
func StrictMatchingOption(o *Options) {
|
||||||
|
o.StrictMatching = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveUnknownServiceOption sets the ResolveUnknownService option. Can be used
|
||||||
|
// as a functional option when resolving endpoints.
|
||||||
|
func ResolveUnknownServiceOption(o *Options) {
|
||||||
|
o.ResolveUnknownService = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// STSRegionalEndpointOption enables the STS endpoint resolver behavior to resolve
|
||||||
|
// STS endpoint to their regional endpoint, instead of the global endpoint.
|
||||||
|
func STSRegionalEndpointOption(o *Options) {
|
||||||
|
o.STSRegionalEndpoint = RegionalSTSEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Resolver provides the interface for functionality to resolve endpoints.
|
||||||
|
// The build in Partition and DefaultResolver return value satisfy this interface.
|
||||||
|
type Resolver interface {
|
||||||
|
EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolverFunc is a helper utility that wraps a function so it satisfies the
|
||||||
|
// Resolver interface. This is useful when you want to add additional endpoint
|
||||||
|
// resolving logic, or stub out specific endpoints with custom values.
|
||||||
|
type ResolverFunc func(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error)
|
||||||
|
|
||||||
|
// EndpointFor wraps the ResolverFunc function to satisfy the Resolver interface.
|
||||||
|
func (fn ResolverFunc) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||||
|
return fn(service, region, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var schemeRE = regexp.MustCompile("^([^:]+)://")
|
||||||
|
|
||||||
|
// AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no
|
||||||
|
// scheme. If disableSSL is true HTTP will set HTTP instead of the default HTTPS.
|
||||||
|
//
|
||||||
|
// If disableSSL is set, it will only set the URL's scheme if the URL does not
|
||||||
|
// contain a scheme.
|
||||||
|
func AddScheme(endpoint string, disableSSL bool) string {
|
||||||
|
if !schemeRE.MatchString(endpoint) {
|
||||||
|
scheme := "https"
|
||||||
|
if disableSSL {
|
||||||
|
scheme = "http"
|
||||||
|
}
|
||||||
|
endpoint = fmt.Sprintf("%s://%s", scheme, endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnumPartitions a provides a way to retrieve the underlying partitions that
|
||||||
|
// make up the SDK's default Resolver, or any resolver decoded from a model
|
||||||
|
// file.
|
||||||
|
//
|
||||||
|
// Use this interface with DefaultResolver and DecodeModels to get the list of
|
||||||
|
// Partitions.
|
||||||
|
type EnumPartitions interface {
|
||||||
|
Partitions() []Partition
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegionsForService returns a map of regions for the partition and service.
|
||||||
|
// If either the partition or service does not exist false will be returned
|
||||||
|
// as the second parameter.
|
||||||
|
//
|
||||||
|
// This example shows how to get the regions for DynamoDB in the AWS partition.
|
||||||
|
//
|
||||||
|
// rs, exists := endpoints.RegionsForService(endpoints.DefaultPartitions(), endpoints.AwsPartitionID, endpoints.DynamodbServiceID)
|
||||||
|
//
|
||||||
|
// This is equivalent to using the partition directly.
|
||||||
|
//
|
||||||
|
// rs := endpoints.AwsPartition().Services()[endpoints.DynamodbServiceID].Regions()
|
||||||
|
func RegionsForService(ps []Partition, partitionID, serviceID string) (map[string]Region, bool) {
|
||||||
|
for _, p := range ps {
|
||||||
|
if p.ID() != partitionID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := p.p.Services[serviceID]; !(ok || serviceID == Ec2metadataServiceID) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
s := Service{
|
||||||
|
id: serviceID,
|
||||||
|
p: p.p,
|
||||||
|
}
|
||||||
|
return s.Regions(), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]Region{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// PartitionForRegion returns the first partition which includes the region
|
||||||
|
// passed in. This includes both known regions and regions which match
|
||||||
|
// a pattern supported by the partition which may include regions that are
|
||||||
|
// not explicitly known by the partition. Use the Regions method of the
|
||||||
|
// returned Partition if explicit support is needed.
|
||||||
|
func PartitionForRegion(ps []Partition, regionID string) (Partition, bool) {
|
||||||
|
for _, p := range ps {
|
||||||
|
if _, ok := p.p.Regions[regionID]; ok || p.p.RegionRegex.MatchString(regionID) {
|
||||||
|
return p, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Partition{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Partition provides the ability to enumerate the partition's regions
|
||||||
|
// and services.
|
||||||
|
type Partition struct {
|
||||||
|
id, dnsSuffix string
|
||||||
|
p *partition
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSSuffix returns the base domain name of the partition.
|
||||||
|
func (p Partition) DNSSuffix() string { return p.dnsSuffix }
|
||||||
|
|
||||||
|
// ID returns the identifier of the partition.
|
||||||
|
func (p Partition) ID() string { return p.id }
|
||||||
|
|
||||||
|
// EndpointFor attempts to resolve the endpoint based on service and region.
|
||||||
|
// See Options for information on configuring how the endpoint is resolved.
|
||||||
|
//
|
||||||
|
// If the service cannot be found in the metadata the UnknownServiceError
|
||||||
|
// error will be returned. This validation will occur regardless if
|
||||||
|
// StrictMatching is enabled. To enable resolving unknown services set the
|
||||||
|
// "ResolveUnknownService" option to true. When StrictMatching is disabled
|
||||||
|
// this option allows the partition resolver to resolve a endpoint based on
|
||||||
|
// the service endpoint ID provided.
|
||||||
|
//
|
||||||
|
// When resolving endpoints you can choose to enable StrictMatching. This will
|
||||||
|
// require the provided service and region to be known by the partition.
|
||||||
|
// If the endpoint cannot be strictly resolved an error will be returned. This
|
||||||
|
// mode is useful to ensure the endpoint resolved is valid. Without
|
||||||
|
// StrictMatching enabled the endpoint returned may look valid but may not work.
|
||||||
|
// StrictMatching requires the SDK to be updated if you want to take advantage
|
||||||
|
// of new regions and services expansions.
|
||||||
|
//
|
||||||
|
// Errors that can be returned.
|
||||||
|
// - UnknownServiceError
|
||||||
|
// - UnknownEndpointError
|
||||||
|
func (p Partition) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||||
|
return p.p.EndpointFor(service, region, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regions returns a map of Regions indexed by their ID. This is useful for
|
||||||
|
// enumerating over the regions in a partition.
|
||||||
|
func (p Partition) Regions() map[string]Region {
|
||||||
|
rs := make(map[string]Region, len(p.p.Regions))
|
||||||
|
for id, r := range p.p.Regions {
|
||||||
|
rs[id] = Region{
|
||||||
|
id: id,
|
||||||
|
desc: r.Description,
|
||||||
|
p: p.p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Services returns a map of Service indexed by their ID. This is useful for
|
||||||
|
// enumerating over the services in a partition.
|
||||||
|
func (p Partition) Services() map[string]Service {
|
||||||
|
ss := make(map[string]Service, len(p.p.Services))
|
||||||
|
|
||||||
|
for id := range p.p.Services {
|
||||||
|
ss[id] = Service{
|
||||||
|
id: id,
|
||||||
|
p: p.p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we have removed the customization that injected this into the model
|
||||||
|
// we still need to pretend that this is a modeled service.
|
||||||
|
if _, ok := ss[Ec2metadataServiceID]; !ok {
|
||||||
|
ss[Ec2metadataServiceID] = Service{
|
||||||
|
id: Ec2metadataServiceID,
|
||||||
|
p: p.p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Region provides information about a region, and ability to resolve an
|
||||||
|
// endpoint from the context of a region, given a service.
|
||||||
|
type Region struct {
|
||||||
|
id, desc string
|
||||||
|
p *partition
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the region's identifier.
|
||||||
|
func (r Region) ID() string { return r.id }
|
||||||
|
|
||||||
|
// Description returns the region's description. The region description
|
||||||
|
// is free text, it can be empty, and it may change between SDK releases.
|
||||||
|
func (r Region) Description() string { return r.desc }
|
||||||
|
|
||||||
|
// ResolveEndpoint resolves an endpoint from the context of the region given
|
||||||
|
// a service. See Partition.EndpointFor for usage and errors that can be returned.
|
||||||
|
func (r Region) ResolveEndpoint(service string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||||
|
return r.p.EndpointFor(service, r.id, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Services returns a list of all services that are known to be in this region.
|
||||||
|
func (r Region) Services() map[string]Service {
|
||||||
|
ss := map[string]Service{}
|
||||||
|
for id, s := range r.p.Services {
|
||||||
|
if _, ok := s.Endpoints[endpointKey{Region: r.id}]; ok {
|
||||||
|
ss[id] = Service{
|
||||||
|
id: id,
|
||||||
|
p: r.p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Service provides information about a service, and ability to resolve an
|
||||||
|
// endpoint from the context of a service, given a region.
|
||||||
|
type Service struct {
|
||||||
|
id string
|
||||||
|
p *partition
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the identifier for the service.
|
||||||
|
func (s Service) ID() string { return s.id }
|
||||||
|
|
||||||
|
// ResolveEndpoint resolves an endpoint from the context of a service given
|
||||||
|
// a region. See Partition.EndpointFor for usage and errors that can be returned.
|
||||||
|
func (s Service) ResolveEndpoint(region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||||
|
return s.p.EndpointFor(s.id, region, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regions returns a map of Regions that the service is present in.
|
||||||
|
//
|
||||||
|
// A region is the AWS region the service exists in. Whereas a Endpoint is
|
||||||
|
// an URL that can be resolved to a instance of a service.
|
||||||
|
func (s Service) Regions() map[string]Region {
|
||||||
|
rs := map[string]Region{}
|
||||||
|
|
||||||
|
service, ok := s.p.Services[s.id]
|
||||||
|
|
||||||
|
// Since ec2metadata customization has been removed we need to check
|
||||||
|
// if it was defined in non-standard endpoints.json file. If it's not
|
||||||
|
// then we can return the empty map as there is no regional-endpoints for IMDS.
|
||||||
|
// Otherwise, we iterate need to iterate the non-standard model.
|
||||||
|
if s.id == Ec2metadataServiceID && !ok {
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
for id := range service.Endpoints {
|
||||||
|
if id.Variant != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r, ok := s.p.Regions[id.Region]; ok {
|
||||||
|
rs[id.Region] = Region{
|
||||||
|
id: id.Region,
|
||||||
|
desc: r.Description,
|
||||||
|
p: s.p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endpoints returns a map of Endpoints indexed by their ID for all known
|
||||||
|
// endpoints for a service.
|
||||||
|
//
|
||||||
|
// A region is the AWS region the service exists in. Whereas a Endpoint is
|
||||||
|
// an URL that can be resolved to a instance of a service.
|
||||||
|
func (s Service) Endpoints() map[string]Endpoint {
|
||||||
|
es := make(map[string]Endpoint, len(s.p.Services[s.id].Endpoints))
|
||||||
|
for id := range s.p.Services[s.id].Endpoints {
|
||||||
|
if id.Variant != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
es[id.Region] = Endpoint{
|
||||||
|
id: id.Region,
|
||||||
|
serviceID: s.id,
|
||||||
|
p: s.p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return es
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Endpoint provides information about endpoints, and provides the ability
|
||||||
|
// to resolve that endpoint for the service, and the region the endpoint
|
||||||
|
// represents.
|
||||||
|
type Endpoint struct {
|
||||||
|
id string
|
||||||
|
serviceID string
|
||||||
|
p *partition
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the identifier for an endpoint.
|
||||||
|
func (e Endpoint) ID() string { return e.id }
|
||||||
|
|
||||||
|
// ServiceID returns the identifier the endpoint belongs to.
|
||||||
|
func (e Endpoint) ServiceID() string { return e.serviceID }
|
||||||
|
|
||||||
|
// ResolveEndpoint resolves an endpoint from the context of a service and
|
||||||
|
// region the endpoint represents. See Partition.EndpointFor for usage and
|
||||||
|
// errors that can be returned.
|
||||||
|
func (e Endpoint) ResolveEndpoint(opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||||
|
return e.p.EndpointFor(e.serviceID, e.id, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A ResolvedEndpoint is an endpoint that has been resolved based on a partition
|
||||||
|
// service, and region.
|
||||||
|
type ResolvedEndpoint struct {
|
||||||
|
// The endpoint URL
|
||||||
|
URL string
|
||||||
|
|
||||||
|
// The endpoint partition
|
||||||
|
PartitionID string
|
||||||
|
|
||||||
|
// The region that should be used for signing requests.
|
||||||
|
SigningRegion string
|
||||||
|
|
||||||
|
// The service name that should be used for signing requests.
|
||||||
|
SigningName string
|
||||||
|
|
||||||
|
// States that the signing name for this endpoint was derived from metadata
|
||||||
|
// passed in, but was not explicitly modeled.
|
||||||
|
SigningNameDerived bool
|
||||||
|
|
||||||
|
// The signing method that should be used for signing requests.
|
||||||
|
SigningMethod string
|
||||||
|
}
|
||||||
|
|
||||||
|
// So that the Error interface type can be included as an anonymous field
|
||||||
|
// in the requestError struct and not conflict with the error.Error() method.
|
||||||
|
type awsError awserr.Error
|
||||||
|
|
||||||
|
// A EndpointNotFoundError is returned when in StrictMatching mode, and the
|
||||||
|
// endpoint for the service and region cannot be found in any of the partitions.
|
||||||
|
type EndpointNotFoundError struct {
|
||||||
|
awsError
|
||||||
|
Partition string
|
||||||
|
Service string
|
||||||
|
Region string
|
||||||
|
}
|
||||||
|
|
||||||
|
// A UnknownServiceError is returned when the service does not resolve to an
|
||||||
|
// endpoint. Includes a list of all known services for the partition. Returned
|
||||||
|
// when a partition does not support the service.
|
||||||
|
type UnknownServiceError struct {
|
||||||
|
awsError
|
||||||
|
Partition string
|
||||||
|
Service string
|
||||||
|
Known []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUnknownServiceError builds and returns UnknownServiceError.
|
||||||
|
func NewUnknownServiceError(p, s string, known []string) UnknownServiceError {
|
||||||
|
return UnknownServiceError{
|
||||||
|
awsError: awserr.New("UnknownServiceError",
|
||||||
|
"could not resolve endpoint for unknown service", nil),
|
||||||
|
Partition: p,
|
||||||
|
Service: s,
|
||||||
|
Known: known,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the error.
|
||||||
|
func (e UnknownServiceError) Error() string {
|
||||||
|
extra := fmt.Sprintf("partition: %q, service: %q",
|
||||||
|
e.Partition, e.Service)
|
||||||
|
if len(e.Known) > 0 {
|
||||||
|
extra += fmt.Sprintf(", known: %v", e.Known)
|
||||||
|
}
|
||||||
|
return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the error.
|
||||||
|
func (e UnknownServiceError) String() string {
|
||||||
|
return e.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A UnknownEndpointError is returned when in StrictMatching mode and the
|
||||||
|
// service is valid, but the region does not resolve to an endpoint. Includes
|
||||||
|
// a list of all known endpoints for the service.
|
||||||
|
type UnknownEndpointError struct {
|
||||||
|
awsError
|
||||||
|
Partition string
|
||||||
|
Service string
|
||||||
|
Region string
|
||||||
|
Known []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUnknownEndpointError builds and returns UnknownEndpointError.
|
||||||
|
func NewUnknownEndpointError(p, s, r string, known []string) UnknownEndpointError {
|
||||||
|
return UnknownEndpointError{
|
||||||
|
awsError: awserr.New("UnknownEndpointError",
|
||||||
|
"could not resolve endpoint", nil),
|
||||||
|
Partition: p,
|
||||||
|
Service: s,
|
||||||
|
Region: r,
|
||||||
|
Known: known,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the error.
|
||||||
|
func (e UnknownEndpointError) Error() string {
|
||||||
|
extra := fmt.Sprintf("partition: %q, service: %q, region: %q",
|
||||||
|
e.Partition, e.Service, e.Region)
|
||||||
|
if len(e.Known) > 0 {
|
||||||
|
extra += fmt.Sprintf(", known: %v", e.Known)
|
||||||
|
}
|
||||||
|
return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the error.
|
||||||
|
func (e UnknownEndpointError) String() string {
|
||||||
|
return e.Error()
|
||||||
|
}
|
24
vendor/github.com/aws/aws-sdk-go/aws/endpoints/legacy_regions.go
generated
vendored
Normal file
24
vendor/github.com/aws/aws-sdk-go/aws/endpoints/legacy_regions.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package endpoints
|
||||||
|
|
||||||
|
var legacyGlobalRegions = map[string]map[string]struct{}{
|
||||||
|
"sts": {
|
||||||
|
"ap-northeast-1": {},
|
||||||
|
"ap-south-1": {},
|
||||||
|
"ap-southeast-1": {},
|
||||||
|
"ap-southeast-2": {},
|
||||||
|
"ca-central-1": {},
|
||||||
|
"eu-central-1": {},
|
||||||
|
"eu-north-1": {},
|
||||||
|
"eu-west-1": {},
|
||||||
|
"eu-west-2": {},
|
||||||
|
"eu-west-3": {},
|
||||||
|
"sa-east-1": {},
|
||||||
|
"us-east-1": {},
|
||||||
|
"us-east-2": {},
|
||||||
|
"us-west-1": {},
|
||||||
|
"us-west-2": {},
|
||||||
|
},
|
||||||
|
"s3": {
|
||||||
|
"us-east-1": {},
|
||||||
|
},
|
||||||
|
}
|
594
vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model.go
generated
vendored
Normal file
594
vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model.go
generated
vendored
Normal file
@ -0,0 +1,594 @@
|
|||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ec2MetadataEndpointIPv6 = "http://[fd00:ec2::254]/latest"
|
||||||
|
ec2MetadataEndpointIPv4 = "http://169.254.169.254/latest"
|
||||||
|
)
|
||||||
|
|
||||||
|
const dnsSuffixTemplateKey = "{dnsSuffix}"
|
||||||
|
|
||||||
|
// defaultKey is a compound map key of a variant and other values.
|
||||||
|
type defaultKey struct {
|
||||||
|
Variant endpointVariant
|
||||||
|
ServiceVariant serviceVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
// endpointKey is a compound map key of a region and associated variant value.
|
||||||
|
type endpointKey struct {
|
||||||
|
Region string
|
||||||
|
Variant endpointVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
// endpointVariant is a bit field to describe the endpoints attributes.
|
||||||
|
type endpointVariant uint64
|
||||||
|
|
||||||
|
// serviceVariant is a bit field to describe the service endpoint attributes.
|
||||||
|
type serviceVariant uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
// fipsVariant indicates that the endpoint is FIPS capable.
|
||||||
|
fipsVariant endpointVariant = 1 << (64 - 1 - iota)
|
||||||
|
|
||||||
|
// dualStackVariant indicates that the endpoint is DualStack capable.
|
||||||
|
dualStackVariant
|
||||||
|
)
|
||||||
|
|
||||||
|
var regionValidationRegex = regexp.MustCompile(`^[[:alnum:]]([[:alnum:]\-]*[[:alnum:]])?$`)
|
||||||
|
|
||||||
|
type partitions []partition
|
||||||
|
|
||||||
|
func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||||
|
var opt Options
|
||||||
|
opt.Set(opts...)
|
||||||
|
|
||||||
|
if len(opt.ResolvedRegion) > 0 {
|
||||||
|
region = opt.ResolvedRegion
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(ps); i++ {
|
||||||
|
if !ps[i].canResolveEndpoint(service, region, opt) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps[i].EndpointFor(service, region, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If loose matching fallback to first partition format to use
|
||||||
|
// when resolving the endpoint.
|
||||||
|
if !opt.StrictMatching && len(ps) > 0 {
|
||||||
|
return ps[0].EndpointFor(service, region, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResolvedEndpoint{}, NewUnknownEndpointError("all partitions", service, region, []string{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partitions satisfies the EnumPartitions interface and returns a list
|
||||||
|
// of Partitions representing each partition represented in the SDK's
|
||||||
|
// endpoints model.
|
||||||
|
func (ps partitions) Partitions() []Partition {
|
||||||
|
parts := make([]Partition, 0, len(ps))
|
||||||
|
for i := 0; i < len(ps); i++ {
|
||||||
|
parts = append(parts, ps[i].Partition())
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
|
||||||
|
type endpointWithVariants struct {
|
||||||
|
endpoint
|
||||||
|
Variants []endpointWithTags `json:"variants"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type endpointWithTags struct {
|
||||||
|
endpoint
|
||||||
|
Tags []string `json:"tags"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type endpointDefaults map[defaultKey]endpoint
|
||||||
|
|
||||||
|
func (p *endpointDefaults) UnmarshalJSON(data []byte) error {
|
||||||
|
if *p == nil {
|
||||||
|
*p = make(endpointDefaults)
|
||||||
|
}
|
||||||
|
|
||||||
|
var e endpointWithVariants
|
||||||
|
if err := json.Unmarshal(data, &e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
(*p)[defaultKey{Variant: 0}] = e.endpoint
|
||||||
|
|
||||||
|
e.Hostname = ""
|
||||||
|
e.DNSSuffix = ""
|
||||||
|
|
||||||
|
for _, variant := range e.Variants {
|
||||||
|
endpointVariant, unknown := parseVariantTags(variant.Tags)
|
||||||
|
if unknown {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var ve endpoint
|
||||||
|
ve.mergeIn(e.endpoint)
|
||||||
|
ve.mergeIn(variant.endpoint)
|
||||||
|
|
||||||
|
(*p)[defaultKey{Variant: endpointVariant}] = ve
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseVariantTags(tags []string) (ev endpointVariant, unknown bool) {
|
||||||
|
if len(tags) == 0 {
|
||||||
|
unknown = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tag := range tags {
|
||||||
|
switch {
|
||||||
|
case strings.EqualFold("fips", tag):
|
||||||
|
ev |= fipsVariant
|
||||||
|
case strings.EqualFold("dualstack", tag):
|
||||||
|
ev |= dualStackVariant
|
||||||
|
default:
|
||||||
|
unknown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ev, unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
type partition struct {
|
||||||
|
ID string `json:"partition"`
|
||||||
|
Name string `json:"partitionName"`
|
||||||
|
DNSSuffix string `json:"dnsSuffix"`
|
||||||
|
RegionRegex regionRegex `json:"regionRegex"`
|
||||||
|
Defaults endpointDefaults `json:"defaults"`
|
||||||
|
Regions regions `json:"regions"`
|
||||||
|
Services services `json:"services"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p partition) Partition() Partition {
|
||||||
|
return Partition{
|
||||||
|
dnsSuffix: p.DNSSuffix,
|
||||||
|
id: p.ID,
|
||||||
|
p: &p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p partition) canResolveEndpoint(service, region string, options Options) bool {
|
||||||
|
s, hasService := p.Services[service]
|
||||||
|
_, hasEndpoint := s.Endpoints[endpointKey{
|
||||||
|
Region: region,
|
||||||
|
Variant: options.getEndpointVariant(service),
|
||||||
|
}]
|
||||||
|
|
||||||
|
if hasEndpoint && hasService {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.StrictMatching {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.RegionRegex.MatchString(region)
|
||||||
|
}
|
||||||
|
|
||||||
|
func allowLegacyEmptyRegion(service string) bool {
|
||||||
|
legacy := map[string]struct{}{
|
||||||
|
"budgets": {},
|
||||||
|
"ce": {},
|
||||||
|
"chime": {},
|
||||||
|
"cloudfront": {},
|
||||||
|
"ec2metadata": {},
|
||||||
|
"iam": {},
|
||||||
|
"importexport": {},
|
||||||
|
"organizations": {},
|
||||||
|
"route53": {},
|
||||||
|
"sts": {},
|
||||||
|
"support": {},
|
||||||
|
"waf": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, allowed := legacy[service]
|
||||||
|
return allowed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) {
|
||||||
|
var opt Options
|
||||||
|
opt.Set(opts...)
|
||||||
|
|
||||||
|
if len(opt.ResolvedRegion) > 0 {
|
||||||
|
region = opt.ResolvedRegion
|
||||||
|
}
|
||||||
|
|
||||||
|
s, hasService := p.Services[service]
|
||||||
|
|
||||||
|
if service == Ec2metadataServiceID && !hasService {
|
||||||
|
endpoint := getEC2MetadataEndpoint(p.ID, service, opt.EC2MetadataEndpointMode)
|
||||||
|
return endpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(service) == 0 || !(hasService || opt.ResolveUnknownService) {
|
||||||
|
// Only return error if the resolver will not fallback to creating
|
||||||
|
// endpoint based on service endpoint ID passed in.
|
||||||
|
return resolved, NewUnknownServiceError(p.ID, service, serviceList(p.Services))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(region) == 0 && allowLegacyEmptyRegion(service) && len(s.PartitionEndpoint) != 0 {
|
||||||
|
region = s.PartitionEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if r, ok := isLegacyGlobalRegion(service, region, opt); ok {
|
||||||
|
region = r
|
||||||
|
}
|
||||||
|
|
||||||
|
variant := opt.getEndpointVariant(service)
|
||||||
|
|
||||||
|
endpoints := s.Endpoints
|
||||||
|
|
||||||
|
serviceDefaults, hasServiceDefault := s.Defaults[defaultKey{Variant: variant}]
|
||||||
|
// If we searched for a variant which may have no explicit service defaults,
|
||||||
|
// then we need to inherit the standard service defaults except the hostname and dnsSuffix
|
||||||
|
if variant != 0 && !hasServiceDefault {
|
||||||
|
serviceDefaults = s.Defaults[defaultKey{}]
|
||||||
|
serviceDefaults.Hostname = ""
|
||||||
|
serviceDefaults.DNSSuffix = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
partitionDefaults, hasPartitionDefault := p.Defaults[defaultKey{Variant: variant}]
|
||||||
|
|
||||||
|
var dnsSuffix string
|
||||||
|
if len(serviceDefaults.DNSSuffix) > 0 {
|
||||||
|
dnsSuffix = serviceDefaults.DNSSuffix
|
||||||
|
} else if variant == 0 {
|
||||||
|
// For legacy reasons the partition dnsSuffix is not in the defaults, so if we looked for
|
||||||
|
// a non-variant endpoint then we need to set the dnsSuffix.
|
||||||
|
dnsSuffix = p.DNSSuffix
|
||||||
|
}
|
||||||
|
|
||||||
|
noDefaults := !hasServiceDefault && !hasPartitionDefault
|
||||||
|
|
||||||
|
e, hasEndpoint := s.endpointForRegion(region, endpoints, variant)
|
||||||
|
if len(region) == 0 || (!hasEndpoint && (opt.StrictMatching || noDefaults)) {
|
||||||
|
return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(endpoints, variant))
|
||||||
|
}
|
||||||
|
|
||||||
|
defs := []endpoint{partitionDefaults, serviceDefaults}
|
||||||
|
|
||||||
|
return e.resolve(service, p.ID, region, dnsSuffixTemplateKey, dnsSuffix, defs, opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEC2MetadataEndpoint(partitionID, service string, mode EC2IMDSEndpointModeState) ResolvedEndpoint {
|
||||||
|
switch mode {
|
||||||
|
case EC2IMDSEndpointModeStateIPv6:
|
||||||
|
return ResolvedEndpoint{
|
||||||
|
URL: ec2MetadataEndpointIPv6,
|
||||||
|
PartitionID: partitionID,
|
||||||
|
SigningRegion: "aws-global",
|
||||||
|
SigningName: service,
|
||||||
|
SigningNameDerived: true,
|
||||||
|
SigningMethod: "v4",
|
||||||
|
}
|
||||||
|
case EC2IMDSEndpointModeStateIPv4:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
return ResolvedEndpoint{
|
||||||
|
URL: ec2MetadataEndpointIPv4,
|
||||||
|
PartitionID: partitionID,
|
||||||
|
SigningRegion: "aws-global",
|
||||||
|
SigningName: service,
|
||||||
|
SigningNameDerived: true,
|
||||||
|
SigningMethod: "v4",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isLegacyGlobalRegion(service string, region string, opt Options) (string, bool) {
|
||||||
|
if opt.getEndpointVariant(service) != 0 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
sts = "sts"
|
||||||
|
s3 = "s3"
|
||||||
|
awsGlobal = "aws-global"
|
||||||
|
)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case service == sts && opt.STSRegionalEndpoint == RegionalSTSEndpoint:
|
||||||
|
return region, false
|
||||||
|
case service == s3 && opt.S3UsEast1RegionalEndpoint == RegionalS3UsEast1Endpoint:
|
||||||
|
return region, false
|
||||||
|
default:
|
||||||
|
if _, ok := legacyGlobalRegions[service][region]; ok {
|
||||||
|
return awsGlobal, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return region, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func serviceList(ss services) []string {
|
||||||
|
list := make([]string, 0, len(ss))
|
||||||
|
for k := range ss {
|
||||||
|
list = append(list, k)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
func endpointList(es serviceEndpoints, variant endpointVariant) []string {
|
||||||
|
list := make([]string, 0, len(es))
|
||||||
|
for k := range es {
|
||||||
|
if k.Variant != variant {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
list = append(list, k.Region)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
type regionRegex struct {
|
||||||
|
*regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rr *regionRegex) UnmarshalJSON(b []byte) (err error) {
|
||||||
|
// Strip leading and trailing quotes
|
||||||
|
regex, err := strconv.Unquote(string(b))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to strip quotes from regex, %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rr.Regexp, err = regexp.Compile(regex)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to unmarshal region regex, %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type regions map[string]region
|
||||||
|
|
||||||
|
type region struct {
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type services map[string]service
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
PartitionEndpoint string `json:"partitionEndpoint"`
|
||||||
|
IsRegionalized boxedBool `json:"isRegionalized,omitempty"`
|
||||||
|
Defaults endpointDefaults `json:"defaults"`
|
||||||
|
Endpoints serviceEndpoints `json:"endpoints"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) endpointForRegion(region string, endpoints serviceEndpoints, variant endpointVariant) (endpoint, bool) {
|
||||||
|
if e, ok := endpoints[endpointKey{Region: region, Variant: variant}]; ok {
|
||||||
|
return e, true
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.IsRegionalized == boxedFalse {
|
||||||
|
return endpoints[endpointKey{Region: s.PartitionEndpoint, Variant: variant}], region == s.PartitionEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unable to find any matching endpoint, return
|
||||||
|
// blank that will be used for generic endpoint creation.
|
||||||
|
return endpoint{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
type serviceEndpoints map[endpointKey]endpoint
|
||||||
|
|
||||||
|
func (s *serviceEndpoints) UnmarshalJSON(data []byte) error {
|
||||||
|
if *s == nil {
|
||||||
|
*s = make(serviceEndpoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
var regionToEndpoint map[string]endpointWithVariants
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, ®ionToEndpoint); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for region, e := range regionToEndpoint {
|
||||||
|
(*s)[endpointKey{Region: region}] = e.endpoint
|
||||||
|
|
||||||
|
e.Hostname = ""
|
||||||
|
e.DNSSuffix = ""
|
||||||
|
|
||||||
|
for _, variant := range e.Variants {
|
||||||
|
endpointVariant, unknown := parseVariantTags(variant.Tags)
|
||||||
|
if unknown {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var ve endpoint
|
||||||
|
ve.mergeIn(e.endpoint)
|
||||||
|
ve.mergeIn(variant.endpoint)
|
||||||
|
|
||||||
|
(*s)[endpointKey{Region: region, Variant: endpointVariant}] = ve
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type endpoint struct {
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
Protocols []string `json:"protocols"`
|
||||||
|
CredentialScope credentialScope `json:"credentialScope"`
|
||||||
|
|
||||||
|
DNSSuffix string `json:"dnsSuffix"`
|
||||||
|
|
||||||
|
// Signature Version not used
|
||||||
|
SignatureVersions []string `json:"signatureVersions"`
|
||||||
|
|
||||||
|
// SSLCommonName not used.
|
||||||
|
SSLCommonName string `json:"sslCommonName"`
|
||||||
|
|
||||||
|
Deprecated boxedBool `json:"deprecated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// isZero returns whether the endpoint structure is an empty (zero) value.
|
||||||
|
func (e endpoint) isZero() bool {
|
||||||
|
switch {
|
||||||
|
case len(e.Hostname) != 0:
|
||||||
|
return false
|
||||||
|
case len(e.Protocols) != 0:
|
||||||
|
return false
|
||||||
|
case e.CredentialScope != (credentialScope{}):
|
||||||
|
return false
|
||||||
|
case len(e.SignatureVersions) != 0:
|
||||||
|
return false
|
||||||
|
case len(e.SSLCommonName) != 0:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultProtocol = "https"
|
||||||
|
defaultSigner = "v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
protocolPriority = []string{"https", "http"}
|
||||||
|
signerPriority = []string{"v4", "v2"}
|
||||||
|
)
|
||||||
|
|
||||||
|
func getByPriority(s []string, p []string, def string) string {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(p); i++ {
|
||||||
|
for j := 0; j < len(s); j++ {
|
||||||
|
if s[j] == p[i] {
|
||||||
|
return s[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e endpoint) resolve(service, partitionID, region, dnsSuffixTemplateVariable, dnsSuffix string, defs []endpoint, opts Options) (ResolvedEndpoint, error) {
|
||||||
|
var merged endpoint
|
||||||
|
for _, def := range defs {
|
||||||
|
merged.mergeIn(def)
|
||||||
|
}
|
||||||
|
merged.mergeIn(e)
|
||||||
|
e = merged
|
||||||
|
|
||||||
|
signingRegion := e.CredentialScope.Region
|
||||||
|
if len(signingRegion) == 0 {
|
||||||
|
signingRegion = region
|
||||||
|
}
|
||||||
|
|
||||||
|
signingName := e.CredentialScope.Service
|
||||||
|
var signingNameDerived bool
|
||||||
|
if len(signingName) == 0 {
|
||||||
|
signingName = service
|
||||||
|
signingNameDerived = true
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname := e.Hostname
|
||||||
|
|
||||||
|
if !validateInputRegion(region) {
|
||||||
|
return ResolvedEndpoint{}, fmt.Errorf("invalid region identifier format provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(merged.DNSSuffix) > 0 {
|
||||||
|
dnsSuffix = merged.DNSSuffix
|
||||||
|
}
|
||||||
|
|
||||||
|
u := strings.Replace(hostname, "{service}", service, 1)
|
||||||
|
u = strings.Replace(u, "{region}", region, 1)
|
||||||
|
u = strings.Replace(u, dnsSuffixTemplateVariable, dnsSuffix, 1)
|
||||||
|
|
||||||
|
scheme := getEndpointScheme(e.Protocols, opts.DisableSSL)
|
||||||
|
u = fmt.Sprintf("%s://%s", scheme, u)
|
||||||
|
|
||||||
|
if e.Deprecated == boxedTrue && opts.LogDeprecated && opts.Logger != nil {
|
||||||
|
opts.Logger.Log(fmt.Sprintf("endpoint identifier %q, url %q marked as deprecated", region, u))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResolvedEndpoint{
|
||||||
|
URL: u,
|
||||||
|
PartitionID: partitionID,
|
||||||
|
SigningRegion: signingRegion,
|
||||||
|
SigningName: signingName,
|
||||||
|
SigningNameDerived: signingNameDerived,
|
||||||
|
SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEndpointScheme(protocols []string, disableSSL bool) string {
|
||||||
|
if disableSSL {
|
||||||
|
return "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
return getByPriority(protocols, protocolPriority, defaultProtocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *endpoint) mergeIn(other endpoint) {
|
||||||
|
if len(other.Hostname) > 0 {
|
||||||
|
e.Hostname = other.Hostname
|
||||||
|
}
|
||||||
|
if len(other.Protocols) > 0 {
|
||||||
|
e.Protocols = other.Protocols
|
||||||
|
}
|
||||||
|
if len(other.SignatureVersions) > 0 {
|
||||||
|
e.SignatureVersions = other.SignatureVersions
|
||||||
|
}
|
||||||
|
if len(other.CredentialScope.Region) > 0 {
|
||||||
|
e.CredentialScope.Region = other.CredentialScope.Region
|
||||||
|
}
|
||||||
|
if len(other.CredentialScope.Service) > 0 {
|
||||||
|
e.CredentialScope.Service = other.CredentialScope.Service
|
||||||
|
}
|
||||||
|
if len(other.SSLCommonName) > 0 {
|
||||||
|
e.SSLCommonName = other.SSLCommonName
|
||||||
|
}
|
||||||
|
if len(other.DNSSuffix) > 0 {
|
||||||
|
e.DNSSuffix = other.DNSSuffix
|
||||||
|
}
|
||||||
|
if other.Deprecated != boxedBoolUnset {
|
||||||
|
e.Deprecated = other.Deprecated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type credentialScope struct {
|
||||||
|
Region string `json:"region"`
|
||||||
|
Service string `json:"service"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type boxedBool int
|
||||||
|
|
||||||
|
func (b *boxedBool) UnmarshalJSON(buf []byte) error {
|
||||||
|
v, err := strconv.ParseBool(string(buf))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if v {
|
||||||
|
*b = boxedTrue
|
||||||
|
} else {
|
||||||
|
*b = boxedFalse
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
boxedBoolUnset boxedBool = iota
|
||||||
|
boxedFalse
|
||||||
|
boxedTrue
|
||||||
|
)
|
||||||
|
|
||||||
|
func validateInputRegion(region string) bool {
|
||||||
|
return regionValidationRegex.MatchString(region)
|
||||||
|
}
|
412
vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go
generated
vendored
Normal file
412
vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go
generated
vendored
Normal file
@ -0,0 +1,412 @@
|
|||||||
|
//go:build codegen
|
||||||
|
// +build codegen
|
||||||
|
|
||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A CodeGenOptions are the options for code generating the endpoints into
|
||||||
|
// Go code from the endpoints model definition.
|
||||||
|
type CodeGenOptions struct {
|
||||||
|
// Options for how the model will be decoded.
|
||||||
|
DecodeModelOptions DecodeModelOptions
|
||||||
|
|
||||||
|
// Disables code generation of the service endpoint prefix IDs defined in
|
||||||
|
// the model.
|
||||||
|
DisableGenerateServiceIDs bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set combines all of the option functions together
|
||||||
|
func (d *CodeGenOptions) Set(optFns ...func(*CodeGenOptions)) {
|
||||||
|
for _, fn := range optFns {
|
||||||
|
fn(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeGenModel given a endpoints model file will decode it and attempt to
|
||||||
|
// generate Go code from the model definition. Error will be returned if
|
||||||
|
// the code is unable to be generated, or decoded.
|
||||||
|
func CodeGenModel(modelFile io.Reader, outFile io.Writer, optFns ...func(*CodeGenOptions)) error {
|
||||||
|
var opts CodeGenOptions
|
||||||
|
opts.Set(optFns...)
|
||||||
|
|
||||||
|
resolver, err := DecodeModel(modelFile, func(d *DecodeModelOptions) {
|
||||||
|
*d = opts.DecodeModelOptions
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := struct {
|
||||||
|
Resolver
|
||||||
|
CodeGenOptions
|
||||||
|
}{
|
||||||
|
Resolver: resolver,
|
||||||
|
CodeGenOptions: opts,
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := template.Must(template.New("tmpl").Funcs(funcMap).Parse(v3Tmpl))
|
||||||
|
if err := tmpl.ExecuteTemplate(outFile, "defaults", v); err != nil {
|
||||||
|
return fmt.Errorf("failed to execute template, %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toSymbol(v string) string {
|
||||||
|
out := []rune{}
|
||||||
|
for _, c := range strings.Title(v) {
|
||||||
|
if !(unicode.IsNumber(c) || unicode.IsLetter(c)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
out = append(out, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func quoteString(v string) string {
|
||||||
|
return fmt.Sprintf("%q", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func regionConstName(p, r string) string {
|
||||||
|
return toSymbol(p) + toSymbol(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func partitionGetter(id string) string {
|
||||||
|
return fmt.Sprintf("%sPartition", toSymbol(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func partitionVarName(id string) string {
|
||||||
|
return fmt.Sprintf("%sPartition", strings.ToLower(toSymbol(id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func listPartitionNames(ps partitions) string {
|
||||||
|
names := []string{}
|
||||||
|
switch len(ps) {
|
||||||
|
case 1:
|
||||||
|
return ps[0].Name
|
||||||
|
case 2:
|
||||||
|
return fmt.Sprintf("%s and %s", ps[0].Name, ps[1].Name)
|
||||||
|
default:
|
||||||
|
for i, p := range ps {
|
||||||
|
if i == len(ps)-1 {
|
||||||
|
names = append(names, "and "+p.Name)
|
||||||
|
} else {
|
||||||
|
names = append(names, p.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(names, ", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func boxedBoolIfSet(msg string, v boxedBool) string {
|
||||||
|
switch v {
|
||||||
|
case boxedTrue:
|
||||||
|
return fmt.Sprintf(msg, "boxedTrue")
|
||||||
|
case boxedFalse:
|
||||||
|
return fmt.Sprintf(msg, "boxedFalse")
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringIfSet(msg, v string) string {
|
||||||
|
if len(v) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf(msg, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringSliceIfSet(msg string, vs []string) string {
|
||||||
|
if len(vs) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
names := []string{}
|
||||||
|
for _, v := range vs {
|
||||||
|
names = append(names, `"`+v+`"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf(msg, strings.Join(names, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
func endpointIsSet(v endpoint) bool {
|
||||||
|
return !reflect.DeepEqual(v, endpoint{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func serviceSet(ps partitions) map[string]struct{} {
|
||||||
|
set := map[string]struct{}{}
|
||||||
|
for _, p := range ps {
|
||||||
|
for id := range p.Services {
|
||||||
|
set[id] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return set
|
||||||
|
}
|
||||||
|
|
||||||
|
func endpointVariantSetter(variant endpointVariant) (string, error) {
|
||||||
|
if variant == 0 {
|
||||||
|
return "0", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if variant > (fipsVariant | dualStackVariant) {
|
||||||
|
return "", fmt.Errorf("unknown endpoint variant")
|
||||||
|
}
|
||||||
|
|
||||||
|
var symbols []string
|
||||||
|
if variant&fipsVariant != 0 {
|
||||||
|
symbols = append(symbols, "fipsVariant")
|
||||||
|
}
|
||||||
|
if variant&dualStackVariant != 0 {
|
||||||
|
symbols = append(symbols, "dualStackVariant")
|
||||||
|
}
|
||||||
|
v := strings.Join(symbols, "|")
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func endpointKeySetter(e endpointKey) (string, error) {
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString("endpointKey{\n")
|
||||||
|
sb.WriteString(fmt.Sprintf("Region: %q,\n", e.Region))
|
||||||
|
if e.Variant != 0 {
|
||||||
|
variantSetter, err := endpointVariantSetter(e.Variant)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
sb.WriteString(fmt.Sprintf("Variant: %s,\n", variantSetter))
|
||||||
|
}
|
||||||
|
sb.WriteString("}")
|
||||||
|
return sb.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultKeySetter(e defaultKey) (string, error) {
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString("defaultKey{\n")
|
||||||
|
if e.Variant != 0 {
|
||||||
|
variantSetter, err := endpointVariantSetter(e.Variant)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
sb.WriteString(fmt.Sprintf("Variant: %s,\n", variantSetter))
|
||||||
|
}
|
||||||
|
sb.WriteString("}")
|
||||||
|
return sb.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var funcMap = template.FuncMap{
|
||||||
|
"ToSymbol": toSymbol,
|
||||||
|
"QuoteString": quoteString,
|
||||||
|
"RegionConst": regionConstName,
|
||||||
|
"PartitionGetter": partitionGetter,
|
||||||
|
"PartitionVarName": partitionVarName,
|
||||||
|
"ListPartitionNames": listPartitionNames,
|
||||||
|
"BoxedBoolIfSet": boxedBoolIfSet,
|
||||||
|
"StringIfSet": stringIfSet,
|
||||||
|
"StringSliceIfSet": stringSliceIfSet,
|
||||||
|
"EndpointIsSet": endpointIsSet,
|
||||||
|
"ServicesSet": serviceSet,
|
||||||
|
"EndpointVariantSetter": endpointVariantSetter,
|
||||||
|
"EndpointKeySetter": endpointKeySetter,
|
||||||
|
"DefaultKeySetter": defaultKeySetter,
|
||||||
|
}
|
||||||
|
|
||||||
|
const v3Tmpl = `
|
||||||
|
{{ define "defaults" -}}
|
||||||
|
// Code generated by aws/endpoints/v3model_codegen.go. DO NOT EDIT.
|
||||||
|
|
||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
{{ template "partition consts" $.Resolver }}
|
||||||
|
|
||||||
|
{{ range $_, $partition := $.Resolver }}
|
||||||
|
{{ template "partition region consts" $partition }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if not $.DisableGenerateServiceIDs -}}
|
||||||
|
{{ template "service consts" $.Resolver }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ template "endpoint resolvers" $.Resolver }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "partition consts" }}
|
||||||
|
// Partition identifiers
|
||||||
|
const (
|
||||||
|
{{ range $_, $p := . -}}
|
||||||
|
{{ ToSymbol $p.ID }}PartitionID = {{ QuoteString $p.ID }} // {{ $p.Name }} partition.
|
||||||
|
{{ end -}}
|
||||||
|
)
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "partition region consts" }}
|
||||||
|
// {{ .Name }} partition's regions.
|
||||||
|
const (
|
||||||
|
{{ range $id, $region := .Regions -}}
|
||||||
|
{{ ToSymbol $id }}RegionID = {{ QuoteString $id }} // {{ $region.Description }}.
|
||||||
|
{{ end -}}
|
||||||
|
)
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "service consts" }}
|
||||||
|
// Service identifiers
|
||||||
|
const (
|
||||||
|
{{ $serviceSet := ServicesSet . -}}
|
||||||
|
{{ range $id, $_ := $serviceSet -}}
|
||||||
|
{{ ToSymbol $id }}ServiceID = {{ QuoteString $id }} // {{ ToSymbol $id }}.
|
||||||
|
{{ end -}}
|
||||||
|
)
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "endpoint resolvers" }}
|
||||||
|
// DefaultResolver returns an Endpoint resolver that will be able
|
||||||
|
// to resolve endpoints for: {{ ListPartitionNames . }}.
|
||||||
|
//
|
||||||
|
// Use DefaultPartitions() to get the list of the default partitions.
|
||||||
|
func DefaultResolver() Resolver {
|
||||||
|
return defaultPartitions
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultPartitions returns a list of the partitions the SDK is bundled
|
||||||
|
// with. The available partitions are: {{ ListPartitionNames . }}.
|
||||||
|
//
|
||||||
|
// partitions := endpoints.DefaultPartitions
|
||||||
|
// for _, p := range partitions {
|
||||||
|
// // ... inspect partitions
|
||||||
|
// }
|
||||||
|
func DefaultPartitions() []Partition {
|
||||||
|
return defaultPartitions.Partitions()
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultPartitions = partitions{
|
||||||
|
{{ range $_, $partition := . -}}
|
||||||
|
{{ PartitionVarName $partition.ID }},
|
||||||
|
{{ end }}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{ range $_, $partition := . -}}
|
||||||
|
{{ $name := PartitionGetter $partition.ID -}}
|
||||||
|
// {{ $name }} returns the Resolver for {{ $partition.Name }}.
|
||||||
|
func {{ $name }}() Partition {
|
||||||
|
return {{ PartitionVarName $partition.ID }}.Partition()
|
||||||
|
}
|
||||||
|
var {{ PartitionVarName $partition.ID }} = {{ template "gocode Partition" $partition }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "default partitions" }}
|
||||||
|
func DefaultPartitions() []Partition {
|
||||||
|
return []partition{
|
||||||
|
{{ range $_, $partition := . -}}
|
||||||
|
// {{ ToSymbol $partition.ID}}Partition(),
|
||||||
|
{{ end }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "gocode Partition" -}}
|
||||||
|
partition{
|
||||||
|
{{ StringIfSet "ID: %q,\n" .ID -}}
|
||||||
|
{{ StringIfSet "Name: %q,\n" .Name -}}
|
||||||
|
{{ StringIfSet "DNSSuffix: %q,\n" .DNSSuffix -}}
|
||||||
|
RegionRegex: {{ template "gocode RegionRegex" .RegionRegex }},
|
||||||
|
{{ if (gt (len .Defaults) 0) -}}
|
||||||
|
Defaults: {{ template "gocode Defaults" .Defaults -}},
|
||||||
|
{{ end -}}
|
||||||
|
Regions: {{ template "gocode Regions" .Regions }},
|
||||||
|
Services: {{ template "gocode Services" .Services }},
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "gocode RegionRegex" -}}
|
||||||
|
regionRegex{
|
||||||
|
Regexp: func() *regexp.Regexp{
|
||||||
|
reg, _ := regexp.Compile({{ QuoteString .Regexp.String }})
|
||||||
|
return reg
|
||||||
|
}(),
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "gocode Regions" -}}
|
||||||
|
regions{
|
||||||
|
{{ range $id, $region := . -}}
|
||||||
|
"{{ $id }}": {{ template "gocode Region" $region }},
|
||||||
|
{{ end -}}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "gocode Region" -}}
|
||||||
|
region{
|
||||||
|
{{ StringIfSet "Description: %q,\n" .Description -}}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "gocode Services" -}}
|
||||||
|
services{
|
||||||
|
{{ range $id, $service := . -}}
|
||||||
|
"{{ $id }}": {{ template "gocode Service" $service }},
|
||||||
|
{{ end }}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "gocode Service" -}}
|
||||||
|
service{
|
||||||
|
{{ StringIfSet "PartitionEndpoint: %q,\n" .PartitionEndpoint -}}
|
||||||
|
{{ BoxedBoolIfSet "IsRegionalized: %s,\n" .IsRegionalized -}}
|
||||||
|
{{ if (gt (len .Defaults) 0) -}}
|
||||||
|
Defaults: {{ template "gocode Defaults" .Defaults -}},
|
||||||
|
{{ end -}}
|
||||||
|
{{ if .Endpoints -}}
|
||||||
|
Endpoints: {{ template "gocode Endpoints" .Endpoints }},
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "gocode Defaults" -}}
|
||||||
|
endpointDefaults{
|
||||||
|
{{ range $id, $endpoint := . -}}
|
||||||
|
{{ DefaultKeySetter $id }}: {{ template "gocode Endpoint" $endpoint }},
|
||||||
|
{{ end }}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "gocode Endpoints" -}}
|
||||||
|
serviceEndpoints{
|
||||||
|
{{ range $id, $endpoint := . -}}
|
||||||
|
{{ EndpointKeySetter $id }}: {{ template "gocode Endpoint" $endpoint }},
|
||||||
|
{{ end }}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "gocode Endpoint" -}}
|
||||||
|
endpoint{
|
||||||
|
{{ StringIfSet "Hostname: %q,\n" .Hostname -}}
|
||||||
|
{{ StringIfSet "DNSSuffix: %q,\n" .DNSSuffix -}}
|
||||||
|
{{ StringIfSet "SSLCommonName: %q,\n" .SSLCommonName -}}
|
||||||
|
{{ StringSliceIfSet "Protocols: []string{%s},\n" .Protocols -}}
|
||||||
|
{{ StringSliceIfSet "SignatureVersions: []string{%s},\n" .SignatureVersions -}}
|
||||||
|
{{ if or .CredentialScope.Region .CredentialScope.Service -}}
|
||||||
|
CredentialScope: credentialScope{
|
||||||
|
{{ StringIfSet "Region: %q,\n" .CredentialScope.Region -}}
|
||||||
|
{{ StringIfSet "Service: %q,\n" .CredentialScope.Service -}}
|
||||||
|
},
|
||||||
|
{{- end }}
|
||||||
|
{{ BoxedBoolIfSet "Deprecated: %s,\n" .Deprecated -}}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
`
|
13
vendor/github.com/aws/aws-sdk-go/aws/errors.go
generated
vendored
Normal file
13
vendor/github.com/aws/aws-sdk-go/aws/errors.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package aws
|
||||||
|
|
||||||
|
import "github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrMissingRegion is an error that is returned if region configuration is
|
||||||
|
// not found.
|
||||||
|
ErrMissingRegion = awserr.New("MissingRegion", "could not find region configuration", nil)
|
||||||
|
|
||||||
|
// ErrMissingEndpoint is an error that is returned if an endpoint cannot be
|
||||||
|
// resolved for a service.
|
||||||
|
ErrMissingEndpoint = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
|
||||||
|
)
|
12
vendor/github.com/aws/aws-sdk-go/aws/jsonvalue.go
generated
vendored
Normal file
12
vendor/github.com/aws/aws-sdk-go/aws/jsonvalue.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package aws
|
||||||
|
|
||||||
|
// JSONValue is a representation of a grab bag type that will be marshaled
|
||||||
|
// into a json string. This type can be used just like any other map.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// values := aws.JSONValue{
|
||||||
|
// "Foo": "Bar",
|
||||||
|
// }
|
||||||
|
// values["Baz"] = "Qux"
|
||||||
|
type JSONValue map[string]interface{}
|
121
vendor/github.com/aws/aws-sdk-go/aws/logger.go
generated
vendored
Normal file
121
vendor/github.com/aws/aws-sdk-go/aws/logger.go
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A LogLevelType defines the level logging should be performed at. Used to instruct
|
||||||
|
// the SDK which statements should be logged.
|
||||||
|
type LogLevelType uint
|
||||||
|
|
||||||
|
// LogLevel returns the pointer to a LogLevel. Should be used to workaround
|
||||||
|
// not being able to take the address of a non-composite literal.
|
||||||
|
func LogLevel(l LogLevelType) *LogLevelType {
|
||||||
|
return &l
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the LogLevel value or the default value LogOff if the LogLevel
|
||||||
|
// is nil. Safe to use on nil value LogLevelTypes.
|
||||||
|
func (l *LogLevelType) Value() LogLevelType {
|
||||||
|
if l != nil {
|
||||||
|
return *l
|
||||||
|
}
|
||||||
|
return LogOff
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches returns true if the v LogLevel is enabled by this LogLevel. Should be
|
||||||
|
// used with logging sub levels. Is safe to use on nil value LogLevelTypes. If
|
||||||
|
// LogLevel is nil, will default to LogOff comparison.
|
||||||
|
func (l *LogLevelType) Matches(v LogLevelType) bool {
|
||||||
|
c := l.Value()
|
||||||
|
return c&v == v
|
||||||
|
}
|
||||||
|
|
||||||
|
// AtLeast returns true if this LogLevel is at least high enough to satisfies v.
|
||||||
|
// Is safe to use on nil value LogLevelTypes. If LogLevel is nil, will default
|
||||||
|
// to LogOff comparison.
|
||||||
|
func (l *LogLevelType) AtLeast(v LogLevelType) bool {
|
||||||
|
c := l.Value()
|
||||||
|
return c >= v
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// LogOff states that no logging should be performed by the SDK. This is the
|
||||||
|
// default state of the SDK, and should be use to disable all logging.
|
||||||
|
LogOff LogLevelType = iota * 0x1000
|
||||||
|
|
||||||
|
// LogDebug state that debug output should be logged by the SDK. This should
|
||||||
|
// be used to inspect request made and responses received.
|
||||||
|
LogDebug
|
||||||
|
)
|
||||||
|
|
||||||
|
// Debug Logging Sub Levels
|
||||||
|
const (
|
||||||
|
// LogDebugWithSigning states that the SDK should log request signing and
|
||||||
|
// presigning events. This should be used to log the signing details of
|
||||||
|
// requests for debugging. Will also enable LogDebug.
|
||||||
|
LogDebugWithSigning LogLevelType = LogDebug | (1 << iota)
|
||||||
|
|
||||||
|
// LogDebugWithHTTPBody states the SDK should log HTTP request and response
|
||||||
|
// HTTP bodys in addition to the headers and path. This should be used to
|
||||||
|
// see the body content of requests and responses made while using the SDK
|
||||||
|
// Will also enable LogDebug.
|
||||||
|
LogDebugWithHTTPBody
|
||||||
|
|
||||||
|
// LogDebugWithRequestRetries states the SDK should log when service requests will
|
||||||
|
// be retried. This should be used to log when you want to log when service
|
||||||
|
// requests are being retried. Will also enable LogDebug.
|
||||||
|
LogDebugWithRequestRetries
|
||||||
|
|
||||||
|
// LogDebugWithRequestErrors states the SDK should log when service requests fail
|
||||||
|
// to build, send, validate, or unmarshal.
|
||||||
|
LogDebugWithRequestErrors
|
||||||
|
|
||||||
|
// LogDebugWithEventStreamBody states the SDK should log EventStream
|
||||||
|
// request and response bodys. This should be used to log the EventStream
|
||||||
|
// wire unmarshaled message content of requests and responses made while
|
||||||
|
// using the SDK Will also enable LogDebug.
|
||||||
|
LogDebugWithEventStreamBody
|
||||||
|
|
||||||
|
// LogDebugWithDeprecated states the SDK should log details about deprecated functionality.
|
||||||
|
LogDebugWithDeprecated
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Logger is a minimalistic interface for the SDK to log messages to. Should
|
||||||
|
// be used to provide custom logging writers for the SDK to use.
|
||||||
|
type Logger interface {
|
||||||
|
Log(...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// A LoggerFunc is a convenience type to convert a function taking a variadic
|
||||||
|
// list of arguments and wrap it so the Logger interface can be used.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// s3.New(sess, &aws.Config{Logger: aws.LoggerFunc(func(args ...interface{}) {
|
||||||
|
// fmt.Fprintln(os.Stdout, args...)
|
||||||
|
// })})
|
||||||
|
type LoggerFunc func(...interface{})
|
||||||
|
|
||||||
|
// Log calls the wrapped function with the arguments provided
|
||||||
|
func (f LoggerFunc) Log(args ...interface{}) {
|
||||||
|
f(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultLogger returns a Logger which will write log messages to stdout, and
|
||||||
|
// use same formatting runes as the stdlib log.Logger
|
||||||
|
func NewDefaultLogger() Logger {
|
||||||
|
return &defaultLogger{
|
||||||
|
logger: log.New(os.Stdout, "", log.LstdFlags),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A defaultLogger provides a minimalistic logger satisfying the Logger interface.
|
||||||
|
type defaultLogger struct {
|
||||||
|
logger *log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log logs the parameters to the stdlib logger. See log.Println.
|
||||||
|
func (l defaultLogger) Log(args ...interface{}) {
|
||||||
|
l.logger.Println(args...)
|
||||||
|
}
|
19
vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error.go
generated
vendored
Normal file
19
vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isErrConnectionReset(err error) bool {
|
||||||
|
if strings.Contains(err.Error(), "read: connection reset") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(err.Error(), "use of closed network connection") ||
|
||||||
|
strings.Contains(err.Error(), "connection reset") ||
|
||||||
|
strings.Contains(err.Error(), "broken pipe") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
346
vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go
generated
vendored
Normal file
346
vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go
generated
vendored
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Handlers provides a collection of request handlers for various
|
||||||
|
// stages of handling requests.
|
||||||
|
type Handlers struct {
|
||||||
|
Validate HandlerList
|
||||||
|
Build HandlerList
|
||||||
|
BuildStream HandlerList
|
||||||
|
Sign HandlerList
|
||||||
|
Send HandlerList
|
||||||
|
ValidateResponse HandlerList
|
||||||
|
Unmarshal HandlerList
|
||||||
|
UnmarshalStream HandlerList
|
||||||
|
UnmarshalMeta HandlerList
|
||||||
|
UnmarshalError HandlerList
|
||||||
|
Retry HandlerList
|
||||||
|
AfterRetry HandlerList
|
||||||
|
CompleteAttempt HandlerList
|
||||||
|
Complete HandlerList
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy returns a copy of this handler's lists.
|
||||||
|
func (h *Handlers) Copy() Handlers {
|
||||||
|
return Handlers{
|
||||||
|
Validate: h.Validate.copy(),
|
||||||
|
Build: h.Build.copy(),
|
||||||
|
BuildStream: h.BuildStream.copy(),
|
||||||
|
Sign: h.Sign.copy(),
|
||||||
|
Send: h.Send.copy(),
|
||||||
|
ValidateResponse: h.ValidateResponse.copy(),
|
||||||
|
Unmarshal: h.Unmarshal.copy(),
|
||||||
|
UnmarshalStream: h.UnmarshalStream.copy(),
|
||||||
|
UnmarshalError: h.UnmarshalError.copy(),
|
||||||
|
UnmarshalMeta: h.UnmarshalMeta.copy(),
|
||||||
|
Retry: h.Retry.copy(),
|
||||||
|
AfterRetry: h.AfterRetry.copy(),
|
||||||
|
CompleteAttempt: h.CompleteAttempt.copy(),
|
||||||
|
Complete: h.Complete.copy(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear removes callback functions for all handlers.
|
||||||
|
func (h *Handlers) Clear() {
|
||||||
|
h.Validate.Clear()
|
||||||
|
h.Build.Clear()
|
||||||
|
h.BuildStream.Clear()
|
||||||
|
h.Send.Clear()
|
||||||
|
h.Sign.Clear()
|
||||||
|
h.Unmarshal.Clear()
|
||||||
|
h.UnmarshalStream.Clear()
|
||||||
|
h.UnmarshalMeta.Clear()
|
||||||
|
h.UnmarshalError.Clear()
|
||||||
|
h.ValidateResponse.Clear()
|
||||||
|
h.Retry.Clear()
|
||||||
|
h.AfterRetry.Clear()
|
||||||
|
h.CompleteAttempt.Clear()
|
||||||
|
h.Complete.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns if there are no handlers in any of the handlerlists.
|
||||||
|
func (h *Handlers) IsEmpty() bool {
|
||||||
|
if h.Validate.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.Build.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.BuildStream.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.Send.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.Sign.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.Unmarshal.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.UnmarshalStream.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.UnmarshalMeta.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.UnmarshalError.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.ValidateResponse.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.Retry.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.AfterRetry.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.CompleteAttempt.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if h.Complete.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// A HandlerListRunItem represents an entry in the HandlerList which
|
||||||
|
// is being run.
|
||||||
|
type HandlerListRunItem struct {
|
||||||
|
Index int
|
||||||
|
Handler NamedHandler
|
||||||
|
Request *Request
|
||||||
|
}
|
||||||
|
|
||||||
|
// A HandlerList manages zero or more handlers in a list.
|
||||||
|
type HandlerList struct {
|
||||||
|
list []NamedHandler
|
||||||
|
|
||||||
|
// Called after each request handler in the list is called. If set
|
||||||
|
// and the func returns true the HandlerList will continue to iterate
|
||||||
|
// over the request handlers. If false is returned the HandlerList
|
||||||
|
// will stop iterating.
|
||||||
|
//
|
||||||
|
// Should be used if extra logic to be performed between each handler
|
||||||
|
// in the list. This can be used to terminate a list's iteration
|
||||||
|
// based on a condition such as error like, HandlerListStopOnError.
|
||||||
|
// Or for logging like HandlerListLogItem.
|
||||||
|
AfterEachFn func(item HandlerListRunItem) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// A NamedHandler is a struct that contains a name and function callback.
|
||||||
|
type NamedHandler struct {
|
||||||
|
Name string
|
||||||
|
Fn func(*Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy creates a copy of the handler list.
|
||||||
|
func (l *HandlerList) copy() HandlerList {
|
||||||
|
n := HandlerList{
|
||||||
|
AfterEachFn: l.AfterEachFn,
|
||||||
|
}
|
||||||
|
if len(l.list) == 0 {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
n.list = append(make([]NamedHandler, 0, len(l.list)), l.list...)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear clears the handler list.
|
||||||
|
func (l *HandlerList) Clear() {
|
||||||
|
l.list = l.list[0:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of handlers in the list.
|
||||||
|
func (l *HandlerList) Len() int {
|
||||||
|
return len(l.list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushBack pushes handler f to the back of the handler list.
|
||||||
|
func (l *HandlerList) PushBack(f func(*Request)) {
|
||||||
|
l.PushBackNamed(NamedHandler{"__anonymous", f})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushBackNamed pushes named handler f to the back of the handler list.
|
||||||
|
func (l *HandlerList) PushBackNamed(n NamedHandler) {
|
||||||
|
if cap(l.list) == 0 {
|
||||||
|
l.list = make([]NamedHandler, 0, 5)
|
||||||
|
}
|
||||||
|
l.list = append(l.list, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushFront pushes handler f to the front of the handler list.
|
||||||
|
func (l *HandlerList) PushFront(f func(*Request)) {
|
||||||
|
l.PushFrontNamed(NamedHandler{"__anonymous", f})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushFrontNamed pushes named handler f to the front of the handler list.
|
||||||
|
func (l *HandlerList) PushFrontNamed(n NamedHandler) {
|
||||||
|
if cap(l.list) == len(l.list) {
|
||||||
|
// Allocating new list required
|
||||||
|
l.list = append([]NamedHandler{n}, l.list...)
|
||||||
|
} else {
|
||||||
|
// Enough room to prepend into list.
|
||||||
|
l.list = append(l.list, NamedHandler{})
|
||||||
|
copy(l.list[1:], l.list)
|
||||||
|
l.list[0] = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes a NamedHandler n
|
||||||
|
func (l *HandlerList) Remove(n NamedHandler) {
|
||||||
|
l.RemoveByName(n.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveByName removes a NamedHandler by name.
|
||||||
|
func (l *HandlerList) RemoveByName(name string) {
|
||||||
|
for i := 0; i < len(l.list); i++ {
|
||||||
|
m := l.list[i]
|
||||||
|
if m.Name == name {
|
||||||
|
// Shift array preventing creating new arrays
|
||||||
|
copy(l.list[i:], l.list[i+1:])
|
||||||
|
l.list[len(l.list)-1] = NamedHandler{}
|
||||||
|
l.list = l.list[:len(l.list)-1]
|
||||||
|
|
||||||
|
// decrement list so next check to length is correct
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SwapNamed will swap out any existing handlers with the same name as the
|
||||||
|
// passed in NamedHandler returning true if handlers were swapped. False is
|
||||||
|
// returned otherwise.
|
||||||
|
func (l *HandlerList) SwapNamed(n NamedHandler) (swapped bool) {
|
||||||
|
for i := 0; i < len(l.list); i++ {
|
||||||
|
if l.list[i].Name == n.Name {
|
||||||
|
l.list[i].Fn = n.Fn
|
||||||
|
swapped = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return swapped
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap will swap out all handlers matching the name passed in. The matched
|
||||||
|
// handlers will be swapped in. True is returned if the handlers were swapped.
|
||||||
|
func (l *HandlerList) Swap(name string, replace NamedHandler) bool {
|
||||||
|
var swapped bool
|
||||||
|
|
||||||
|
for i := 0; i < len(l.list); i++ {
|
||||||
|
if l.list[i].Name == name {
|
||||||
|
l.list[i] = replace
|
||||||
|
swapped = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return swapped
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBackNamed will replace the named handler if it exists in the handler list.
|
||||||
|
// If the handler does not exist the handler will be added to the end of the list.
|
||||||
|
func (l *HandlerList) SetBackNamed(n NamedHandler) {
|
||||||
|
if !l.SwapNamed(n) {
|
||||||
|
l.PushBackNamed(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFrontNamed will replace the named handler if it exists in the handler list.
|
||||||
|
// If the handler does not exist the handler will be added to the beginning of
|
||||||
|
// the list.
|
||||||
|
func (l *HandlerList) SetFrontNamed(n NamedHandler) {
|
||||||
|
if !l.SwapNamed(n) {
|
||||||
|
l.PushFrontNamed(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run executes all handlers in the list with a given request object.
|
||||||
|
func (l *HandlerList) Run(r *Request) {
|
||||||
|
for i, h := range l.list {
|
||||||
|
h.Fn(r)
|
||||||
|
item := HandlerListRunItem{
|
||||||
|
Index: i, Handler: h, Request: r,
|
||||||
|
}
|
||||||
|
if l.AfterEachFn != nil && !l.AfterEachFn(item) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerListLogItem logs the request handler and the state of the
|
||||||
|
// request's Error value. Always returns true to continue iterating
|
||||||
|
// request handlers in a HandlerList.
|
||||||
|
func HandlerListLogItem(item HandlerListRunItem) bool {
|
||||||
|
if item.Request.Config.Logger == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
item.Request.Config.Logger.Log("DEBUG: RequestHandler",
|
||||||
|
item.Index, item.Handler.Name, item.Request.Error)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerListStopOnError returns false to stop the HandlerList iterating
|
||||||
|
// over request handlers if Request.Error is not nil. True otherwise
|
||||||
|
// to continue iterating.
|
||||||
|
func HandlerListStopOnError(item HandlerListRunItem) bool {
|
||||||
|
return item.Request.Error == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAppendUserAgent will add a string to the user agent prefixed with a
|
||||||
|
// single white space.
|
||||||
|
func WithAppendUserAgent(s string) Option {
|
||||||
|
return func(r *Request) {
|
||||||
|
r.Handlers.Build.PushBack(func(r2 *Request) {
|
||||||
|
AddToUserAgent(r, s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeAddToUserAgentHandler will add the name/version pair to the User-Agent request
|
||||||
|
// header. If the extra parameters are provided they will be added as metadata to the
|
||||||
|
// name/version pair resulting in the following format.
|
||||||
|
// "name/version (extra0; extra1; ...)"
|
||||||
|
// The user agent part will be concatenated with this current request's user agent string.
|
||||||
|
func MakeAddToUserAgentHandler(name, version string, extra ...string) func(*Request) {
|
||||||
|
ua := fmt.Sprintf("%s/%s", name, version)
|
||||||
|
if len(extra) > 0 {
|
||||||
|
ua += fmt.Sprintf(" (%s)", strings.Join(extra, "; "))
|
||||||
|
}
|
||||||
|
return func(r *Request) {
|
||||||
|
AddToUserAgent(r, ua)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeAddToUserAgentFreeFormHandler adds the input to the User-Agent request header.
|
||||||
|
// The input string will be concatenated with the current request's user agent string.
|
||||||
|
func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
|
||||||
|
return func(r *Request) {
|
||||||
|
AddToUserAgent(r, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSetRequestHeaders updates the operation request's HTTP header to contain
|
||||||
|
// the header key value pairs provided. If the header key already exists in the
|
||||||
|
// request's HTTP header set, the existing value(s) will be replaced.
|
||||||
|
//
|
||||||
|
// Header keys added will be added as canonical format with title casing
|
||||||
|
// applied via http.Header.Set method.
|
||||||
|
func WithSetRequestHeaders(h map[string]string) Option {
|
||||||
|
return withRequestHeader(h).SetRequestHeaders
|
||||||
|
}
|
||||||
|
|
||||||
|
type withRequestHeader map[string]string
|
||||||
|
|
||||||
|
func (h withRequestHeader) SetRequestHeaders(r *Request) {
|
||||||
|
for k, v := range h {
|
||||||
|
r.HTTPRequest.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
}
|
24
vendor/github.com/aws/aws-sdk-go/aws/request/http_request.go
generated
vendored
Normal file
24
vendor/github.com/aws/aws-sdk-go/aws/request/http_request.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
func copyHTTPRequest(r *http.Request, body io.ReadCloser) *http.Request {
|
||||||
|
req := new(http.Request)
|
||||||
|
*req = *r
|
||||||
|
req.URL = &url.URL{}
|
||||||
|
*req.URL = *r.URL
|
||||||
|
req.Body = body
|
||||||
|
|
||||||
|
req.Header = http.Header{}
|
||||||
|
for k, v := range r.Header {
|
||||||
|
for _, vv := range v {
|
||||||
|
req.Header.Add(k, vv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return req
|
||||||
|
}
|
65
vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader.go
generated
vendored
Normal file
65
vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/internal/sdkio"
|
||||||
|
)
|
||||||
|
|
||||||
|
// offsetReader is a thread-safe io.ReadCloser to prevent racing
|
||||||
|
// with retrying requests
|
||||||
|
type offsetReader struct {
|
||||||
|
buf io.ReadSeeker
|
||||||
|
lock sync.Mutex
|
||||||
|
closed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOffsetReader(buf io.ReadSeeker, offset int64) (*offsetReader, error) {
|
||||||
|
reader := &offsetReader{}
|
||||||
|
_, err := buf.Seek(offset, sdkio.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.buf = buf
|
||||||
|
return reader, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close will close the instance of the offset reader's access to
|
||||||
|
// the underlying io.ReadSeeker.
|
||||||
|
func (o *offsetReader) Close() error {
|
||||||
|
o.lock.Lock()
|
||||||
|
defer o.lock.Unlock()
|
||||||
|
o.closed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read is a thread-safe read of the underlying io.ReadSeeker
|
||||||
|
func (o *offsetReader) Read(p []byte) (int, error) {
|
||||||
|
o.lock.Lock()
|
||||||
|
defer o.lock.Unlock()
|
||||||
|
|
||||||
|
if o.closed {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.buf.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek is a thread-safe seeking operation.
|
||||||
|
func (o *offsetReader) Seek(offset int64, whence int) (int64, error) {
|
||||||
|
o.lock.Lock()
|
||||||
|
defer o.lock.Unlock()
|
||||||
|
|
||||||
|
return o.buf.Seek(offset, whence)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseAndCopy will return a new offsetReader with a copy of the old buffer
|
||||||
|
// and close the old buffer.
|
||||||
|
func (o *offsetReader) CloseAndCopy(offset int64) (*offsetReader, error) {
|
||||||
|
if err := o.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newOffsetReader(o.buf, offset)
|
||||||
|
}
|
722
vendor/github.com/aws/aws-sdk-go/aws/request/request.go
generated
vendored
Normal file
722
vendor/github.com/aws/aws-sdk-go/aws/request/request.go
generated
vendored
Normal file
@ -0,0 +1,722 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/sdkio"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ErrCodeSerialization is the serialization error code that is received
|
||||||
|
// during protocol unmarshaling.
|
||||||
|
ErrCodeSerialization = "SerializationError"
|
||||||
|
|
||||||
|
// ErrCodeRead is an error that is returned during HTTP reads.
|
||||||
|
ErrCodeRead = "ReadError"
|
||||||
|
|
||||||
|
// ErrCodeResponseTimeout is the connection timeout error that is received
|
||||||
|
// during body reads.
|
||||||
|
ErrCodeResponseTimeout = "ResponseTimeout"
|
||||||
|
|
||||||
|
// ErrCodeInvalidPresignExpire is returned when the expire time provided to
|
||||||
|
// presign is invalid
|
||||||
|
ErrCodeInvalidPresignExpire = "InvalidPresignExpireError"
|
||||||
|
|
||||||
|
// CanceledErrorCode is the error code that will be returned by an
|
||||||
|
// API request that was canceled. Requests given a aws.Context may
|
||||||
|
// return this error when canceled.
|
||||||
|
CanceledErrorCode = "RequestCanceled"
|
||||||
|
|
||||||
|
// ErrCodeRequestError is an error preventing the SDK from continuing to
|
||||||
|
// process the request.
|
||||||
|
ErrCodeRequestError = "RequestError"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Request is the service request to be made.
|
||||||
|
type Request struct {
|
||||||
|
Config aws.Config
|
||||||
|
ClientInfo metadata.ClientInfo
|
||||||
|
Handlers Handlers
|
||||||
|
|
||||||
|
Retryer
|
||||||
|
AttemptTime time.Time
|
||||||
|
Time time.Time
|
||||||
|
Operation *Operation
|
||||||
|
HTTPRequest *http.Request
|
||||||
|
HTTPResponse *http.Response
|
||||||
|
Body io.ReadSeeker
|
||||||
|
streamingBody io.ReadCloser
|
||||||
|
BodyStart int64 // offset from beginning of Body that the request body starts
|
||||||
|
Params interface{}
|
||||||
|
Error error
|
||||||
|
Data interface{}
|
||||||
|
RequestID string
|
||||||
|
RetryCount int
|
||||||
|
Retryable *bool
|
||||||
|
RetryDelay time.Duration
|
||||||
|
NotHoist bool
|
||||||
|
SignedHeaderVals http.Header
|
||||||
|
LastSignedAt time.Time
|
||||||
|
DisableFollowRedirects bool
|
||||||
|
|
||||||
|
// Additional API error codes that should be retried. IsErrorRetryable
|
||||||
|
// will consider these codes in addition to its built in cases.
|
||||||
|
RetryErrorCodes []string
|
||||||
|
|
||||||
|
// Additional API error codes that should be retried with throttle backoff
|
||||||
|
// delay. IsErrorThrottle will consider these codes in addition to its
|
||||||
|
// built in cases.
|
||||||
|
ThrottleErrorCodes []string
|
||||||
|
|
||||||
|
// A value greater than 0 instructs the request to be signed as Presigned URL
|
||||||
|
// You should not set this field directly. Instead use Request's
|
||||||
|
// Presign or PresignRequest methods.
|
||||||
|
ExpireTime time.Duration
|
||||||
|
|
||||||
|
context aws.Context
|
||||||
|
|
||||||
|
built bool
|
||||||
|
|
||||||
|
// Need to persist an intermediate body between the input Body and HTTP
|
||||||
|
// request body because the HTTP Client's transport can maintain a reference
|
||||||
|
// to the HTTP request's body after the client has returned. This value is
|
||||||
|
// safe to use concurrently and wrap the input Body for each HTTP request.
|
||||||
|
safeBody *offsetReader
|
||||||
|
}
|
||||||
|
|
||||||
|
// An Operation is the service API operation to be made.
|
||||||
|
type Operation struct {
|
||||||
|
Name string
|
||||||
|
HTTPMethod string
|
||||||
|
HTTPPath string
|
||||||
|
*Paginator
|
||||||
|
|
||||||
|
BeforePresignFn func(r *Request) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new Request pointer for the service API operation and
|
||||||
|
// parameters.
|
||||||
|
//
|
||||||
|
// A Retryer should be provided to direct how the request is retried. If
|
||||||
|
// Retryer is nil, a default no retry value will be used. You can use
|
||||||
|
// NoOpRetryer in the Client package to disable retry behavior directly.
|
||||||
|
//
|
||||||
|
// Params is any value of input parameters to be the request payload.
|
||||||
|
// Data is pointer value to an object which the request's response
|
||||||
|
// payload will be deserialized to.
|
||||||
|
func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
|
||||||
|
retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
|
||||||
|
|
||||||
|
if retryer == nil {
|
||||||
|
retryer = noOpRetryer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
method := operation.HTTPMethod
|
||||||
|
if method == "" {
|
||||||
|
method = "POST"
|
||||||
|
}
|
||||||
|
|
||||||
|
httpReq, _ := http.NewRequest(method, "", nil)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
httpReq.URL, err = url.Parse(clientInfo.Endpoint)
|
||||||
|
if err != nil {
|
||||||
|
httpReq.URL = &url.URL{}
|
||||||
|
err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(operation.HTTPPath) != 0 {
|
||||||
|
opHTTPPath := operation.HTTPPath
|
||||||
|
var opQueryString string
|
||||||
|
if idx := strings.Index(opHTTPPath, "?"); idx >= 0 {
|
||||||
|
opQueryString = opHTTPPath[idx+1:]
|
||||||
|
opHTTPPath = opHTTPPath[:idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(httpReq.URL.Path, "/") && strings.HasPrefix(opHTTPPath, "/") {
|
||||||
|
opHTTPPath = opHTTPPath[1:]
|
||||||
|
}
|
||||||
|
httpReq.URL.Path += opHTTPPath
|
||||||
|
httpReq.URL.RawQuery = opQueryString
|
||||||
|
}
|
||||||
|
|
||||||
|
r := &Request{
|
||||||
|
Config: cfg,
|
||||||
|
ClientInfo: clientInfo,
|
||||||
|
Handlers: handlers.Copy(),
|
||||||
|
|
||||||
|
Retryer: retryer,
|
||||||
|
Time: time.Now(),
|
||||||
|
ExpireTime: 0,
|
||||||
|
Operation: operation,
|
||||||
|
HTTPRequest: httpReq,
|
||||||
|
Body: nil,
|
||||||
|
Params: params,
|
||||||
|
Error: err,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
r.SetBufferBody([]byte{})
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Option is a functional option that can augment or modify a request when
|
||||||
|
// using a WithContext API operation method.
|
||||||
|
type Option func(*Request)
|
||||||
|
|
||||||
|
// WithGetResponseHeader builds a request Option which will retrieve a single
|
||||||
|
// header value from the HTTP Response. If there are multiple values for the
|
||||||
|
// header key use WithGetResponseHeaders instead to access the http.Header
|
||||||
|
// map directly. The passed in val pointer must be non-nil.
|
||||||
|
//
|
||||||
|
// This Option can be used multiple times with a single API operation.
|
||||||
|
//
|
||||||
|
// var id2, versionID string
|
||||||
|
// svc.PutObjectWithContext(ctx, params,
|
||||||
|
// request.WithGetResponseHeader("x-amz-id-2", &id2),
|
||||||
|
// request.WithGetResponseHeader("x-amz-version-id", &versionID),
|
||||||
|
// )
|
||||||
|
func WithGetResponseHeader(key string, val *string) Option {
|
||||||
|
return func(r *Request) {
|
||||||
|
r.Handlers.Complete.PushBack(func(req *Request) {
|
||||||
|
*val = req.HTTPResponse.Header.Get(key)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGetResponseHeaders builds a request Option which will retrieve the
|
||||||
|
// headers from the HTTP response and assign them to the passed in headers
|
||||||
|
// variable. The passed in headers pointer must be non-nil.
|
||||||
|
//
|
||||||
|
// var headers http.Header
|
||||||
|
// svc.PutObjectWithContext(ctx, params, request.WithGetResponseHeaders(&headers))
|
||||||
|
func WithGetResponseHeaders(headers *http.Header) Option {
|
||||||
|
return func(r *Request) {
|
||||||
|
r.Handlers.Complete.PushBack(func(req *Request) {
|
||||||
|
*headers = req.HTTPResponse.Header
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLogLevel is a request option that will set the request to use a specific
|
||||||
|
// log level when the request is made.
|
||||||
|
//
|
||||||
|
// svc.PutObjectWithContext(ctx, params, request.WithLogLevel(aws.LogDebugWithHTTPBody)
|
||||||
|
func WithLogLevel(l aws.LogLevelType) Option {
|
||||||
|
return func(r *Request) {
|
||||||
|
r.Config.LogLevel = aws.LogLevel(l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyOptions will apply each option to the request calling them in the order
|
||||||
|
// the were provided.
|
||||||
|
func (r *Request) ApplyOptions(opts ...Option) {
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context will always returns a non-nil context. If Request does not have a
|
||||||
|
// context aws.BackgroundContext will be returned.
|
||||||
|
func (r *Request) Context() aws.Context {
|
||||||
|
if r.context != nil {
|
||||||
|
return r.context
|
||||||
|
}
|
||||||
|
return aws.BackgroundContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContext adds a Context to the current request that can be used to cancel
|
||||||
|
// a in-flight request. The Context value must not be nil, or this method will
|
||||||
|
// panic.
|
||||||
|
//
|
||||||
|
// Unlike http.Request.WithContext, SetContext does not return a copy of the
|
||||||
|
// Request. It is not safe to use use a single Request value for multiple
|
||||||
|
// requests. A new Request should be created for each API operation request.
|
||||||
|
//
|
||||||
|
// Go 1.6 and below:
|
||||||
|
// The http.Request's Cancel field will be set to the Done() value of
|
||||||
|
// the context. This will overwrite the Cancel field's value.
|
||||||
|
//
|
||||||
|
// Go 1.7 and above:
|
||||||
|
// The http.Request.WithContext will be used to set the context on the underlying
|
||||||
|
// http.Request. This will create a shallow copy of the http.Request. The SDK
|
||||||
|
// may create sub contexts in the future for nested requests such as retries.
|
||||||
|
func (r *Request) SetContext(ctx aws.Context) {
|
||||||
|
if ctx == nil {
|
||||||
|
panic("context cannot be nil")
|
||||||
|
}
|
||||||
|
setRequestContext(r, ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WillRetry returns if the request's can be retried.
|
||||||
|
func (r *Request) WillRetry() bool {
|
||||||
|
if !aws.IsReaderSeekable(r.Body) && r.HTTPRequest.Body != NoBody {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return r.Error != nil && aws.BoolValue(r.Retryable) && r.RetryCount < r.MaxRetries()
|
||||||
|
}
|
||||||
|
|
||||||
|
func fmtAttemptCount(retryCount, maxRetries int) string {
|
||||||
|
return fmt.Sprintf("attempt %v/%v", retryCount, maxRetries)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParamsFilled returns if the request's parameters have been populated
|
||||||
|
// and the parameters are valid. False is returned if no parameters are
|
||||||
|
// provided or invalid.
|
||||||
|
func (r *Request) ParamsFilled() bool {
|
||||||
|
return r.Params != nil && reflect.ValueOf(r.Params).Elem().IsValid()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataFilled returns true if the request's data for response deserialization
|
||||||
|
// target has been set and is a valid. False is returned if data is not
|
||||||
|
// set, or is invalid.
|
||||||
|
func (r *Request) DataFilled() bool {
|
||||||
|
return r.Data != nil && reflect.ValueOf(r.Data).Elem().IsValid()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBufferBody will set the request's body bytes that will be sent to
|
||||||
|
// the service API.
|
||||||
|
func (r *Request) SetBufferBody(buf []byte) {
|
||||||
|
r.SetReaderBody(bytes.NewReader(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStringBody sets the body of the request to be backed by a string.
|
||||||
|
func (r *Request) SetStringBody(s string) {
|
||||||
|
r.SetReaderBody(strings.NewReader(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetReaderBody will set the request's body reader.
|
||||||
|
func (r *Request) SetReaderBody(reader io.ReadSeeker) {
|
||||||
|
r.Body = reader
|
||||||
|
|
||||||
|
if aws.IsReaderSeekable(reader) {
|
||||||
|
var err error
|
||||||
|
// Get the Bodies current offset so retries will start from the same
|
||||||
|
// initial position.
|
||||||
|
r.BodyStart, err = reader.Seek(0, sdkio.SeekCurrent)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New(ErrCodeSerialization,
|
||||||
|
"failed to determine start of request body", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.ResetBody()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStreamingBody set the reader to be used for the request that will stream
|
||||||
|
// bytes to the server. Request's Body must not be set to any reader.
|
||||||
|
func (r *Request) SetStreamingBody(reader io.ReadCloser) {
|
||||||
|
r.streamingBody = reader
|
||||||
|
r.SetReaderBody(aws.ReadSeekCloser(reader))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Presign returns the request's signed URL. Error will be returned
|
||||||
|
// if the signing fails. The expire parameter is only used for presigned Amazon
|
||||||
|
// S3 API requests. All other AWS services will use a fixed expiration
|
||||||
|
// time of 15 minutes.
|
||||||
|
//
|
||||||
|
// It is invalid to create a presigned URL with a expire duration 0 or less. An
|
||||||
|
// error is returned if expire duration is 0 or less.
|
||||||
|
func (r *Request) Presign(expire time.Duration) (string, error) {
|
||||||
|
r = r.copy()
|
||||||
|
|
||||||
|
// Presign requires all headers be hoisted. There is no way to retrieve
|
||||||
|
// the signed headers not hoisted without this. Making the presigned URL
|
||||||
|
// useless.
|
||||||
|
r.NotHoist = false
|
||||||
|
|
||||||
|
u, _, err := getPresignedURL(r, expire)
|
||||||
|
return u, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// PresignRequest behaves just like presign, with the addition of returning a
|
||||||
|
// set of headers that were signed. The expire parameter is only used for
|
||||||
|
// presigned Amazon S3 API requests. All other AWS services will use a fixed
|
||||||
|
// expiration time of 15 minutes.
|
||||||
|
//
|
||||||
|
// It is invalid to create a presigned URL with a expire duration 0 or less. An
|
||||||
|
// error is returned if expire duration is 0 or less.
|
||||||
|
//
|
||||||
|
// Returns the URL string for the API operation with signature in the query string,
|
||||||
|
// and the HTTP headers that were included in the signature. These headers must
|
||||||
|
// be included in any HTTP request made with the presigned URL.
|
||||||
|
//
|
||||||
|
// To prevent hoisting any headers to the query string set NotHoist to true on
|
||||||
|
// this Request value prior to calling PresignRequest.
|
||||||
|
func (r *Request) PresignRequest(expire time.Duration) (string, http.Header, error) {
|
||||||
|
r = r.copy()
|
||||||
|
return getPresignedURL(r, expire)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPresigned returns true if the request represents a presigned API url.
|
||||||
|
func (r *Request) IsPresigned() bool {
|
||||||
|
return r.ExpireTime != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPresignedURL(r *Request, expire time.Duration) (string, http.Header, error) {
|
||||||
|
if expire <= 0 {
|
||||||
|
return "", nil, awserr.New(
|
||||||
|
ErrCodeInvalidPresignExpire,
|
||||||
|
"presigned URL requires an expire duration greater than 0",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.ExpireTime = expire
|
||||||
|
|
||||||
|
if r.Operation.BeforePresignFn != nil {
|
||||||
|
if err := r.Operation.BeforePresignFn(r); err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.Sign(); err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.HTTPRequest.URL.String(), r.SignedHeaderVals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
notRetrying = "not retrying"
|
||||||
|
)
|
||||||
|
|
||||||
|
func debugLogReqError(r *Request, stage, retryStr string, err error) {
|
||||||
|
if !r.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Config.Logger.Log(fmt.Sprintf("DEBUG: %s %s/%s failed, %s, error %v",
|
||||||
|
stage, r.ClientInfo.ServiceName, r.Operation.Name, retryStr, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build will build the request's object so it can be signed and sent
|
||||||
|
// to the service. Build will also validate all the request's parameters.
|
||||||
|
// Any additional build Handlers set on this request will be run
|
||||||
|
// in the order they were set.
|
||||||
|
//
|
||||||
|
// The request will only be built once. Multiple calls to build will have
|
||||||
|
// no effect.
|
||||||
|
//
|
||||||
|
// If any Validate or Build errors occur the build will stop and the error
|
||||||
|
// which occurred will be returned.
|
||||||
|
func (r *Request) Build() error {
|
||||||
|
if !r.built {
|
||||||
|
r.Handlers.Validate.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
debugLogReqError(r, "Validate Request", notRetrying, r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
r.Handlers.Build.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
debugLogReqError(r, "Build Request", notRetrying, r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
r.built = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign will sign the request, returning error if errors are encountered.
|
||||||
|
//
|
||||||
|
// Sign will build the request prior to signing. All Sign Handlers will
|
||||||
|
// be executed in the order they were set.
|
||||||
|
func (r *Request) Sign() error {
|
||||||
|
r.Build()
|
||||||
|
if r.Error != nil {
|
||||||
|
debugLogReqError(r, "Build Request", notRetrying, r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
SanitizeHostForHeader(r.HTTPRequest)
|
||||||
|
|
||||||
|
r.Handlers.Sign.Run(r)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) getNextRequestBody() (body io.ReadCloser, err error) {
|
||||||
|
if r.streamingBody != nil {
|
||||||
|
return r.streamingBody, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.safeBody != nil {
|
||||||
|
r.safeBody.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
r.safeBody, err = newOffsetReader(r.Body, r.BodyStart)
|
||||||
|
if err != nil {
|
||||||
|
return nil, awserr.New(ErrCodeSerialization,
|
||||||
|
"failed to get next request body reader", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go 1.8 tightened and clarified the rules code needs to use when building
|
||||||
|
// requests with the http package. Go 1.8 removed the automatic detection
|
||||||
|
// of if the Request.Body was empty, or actually had bytes in it. The SDK
|
||||||
|
// always sets the Request.Body even if it is empty and should not actually
|
||||||
|
// be sent. This is incorrect.
|
||||||
|
//
|
||||||
|
// Go 1.8 did add a http.NoBody value that the SDK can use to tell the http
|
||||||
|
// client that the request really should be sent without a body. The
|
||||||
|
// Request.Body cannot be set to nil, which is preferable, because the
|
||||||
|
// field is exported and could introduce nil pointer dereferences for users
|
||||||
|
// of the SDK if they used that field.
|
||||||
|
//
|
||||||
|
// Related golang/go#18257
|
||||||
|
l, err := aws.SeekerLen(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, awserr.New(ErrCodeSerialization,
|
||||||
|
"failed to compute request body size", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if l == 0 {
|
||||||
|
body = NoBody
|
||||||
|
} else if l > 0 {
|
||||||
|
body = r.safeBody
|
||||||
|
} else {
|
||||||
|
// Hack to prevent sending bodies for methods where the body
|
||||||
|
// should be ignored by the server. Sending bodies on these
|
||||||
|
// methods without an associated ContentLength will cause the
|
||||||
|
// request to socket timeout because the server does not handle
|
||||||
|
// Transfer-Encoding: chunked bodies for these methods.
|
||||||
|
//
|
||||||
|
// This would only happen if a aws.ReaderSeekerCloser was used with
|
||||||
|
// a io.Reader that was not also an io.Seeker, or did not implement
|
||||||
|
// Len() method.
|
||||||
|
switch r.Operation.HTTPMethod {
|
||||||
|
case "GET", "HEAD", "DELETE":
|
||||||
|
body = NoBody
|
||||||
|
default:
|
||||||
|
body = r.safeBody
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBody will return an io.ReadSeeker of the Request's underlying
|
||||||
|
// input body with a concurrency safe wrapper.
|
||||||
|
func (r *Request) GetBody() io.ReadSeeker {
|
||||||
|
return r.safeBody
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send will send the request, returning error if errors are encountered.
|
||||||
|
//
|
||||||
|
// Send will sign the request prior to sending. All Send Handlers will
|
||||||
|
// be executed in the order they were set.
|
||||||
|
//
|
||||||
|
// Canceling a request is non-deterministic. If a request has been canceled,
|
||||||
|
// then the transport will choose, randomly, one of the state channels during
|
||||||
|
// reads or getting the connection.
|
||||||
|
//
|
||||||
|
// readLoop() and getConn(req *Request, cm connectMethod)
|
||||||
|
// https://github.com/golang/go/blob/master/src/net/http/transport.go
|
||||||
|
//
|
||||||
|
// Send will not close the request.Request's body.
|
||||||
|
func (r *Request) Send() error {
|
||||||
|
defer func() {
|
||||||
|
// Ensure a non-nil HTTPResponse parameter is set to ensure handlers
|
||||||
|
// checking for HTTPResponse values, don't fail.
|
||||||
|
if r.HTTPResponse == nil {
|
||||||
|
r.HTTPResponse = &http.Response{
|
||||||
|
Header: http.Header{},
|
||||||
|
Body: ioutil.NopCloser(&bytes.Buffer{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Regardless of success or failure of the request trigger the Complete
|
||||||
|
// request handlers.
|
||||||
|
r.Handlers.Complete.Run(r)
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := r.Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
r.Error = nil
|
||||||
|
r.AttemptTime = time.Now()
|
||||||
|
|
||||||
|
if err := r.Sign(); err != nil {
|
||||||
|
debugLogReqError(r, "Sign Request", notRetrying, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.sendRequest(); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r.Handlers.Retry.Run(r)
|
||||||
|
r.Handlers.AfterRetry.Run(r)
|
||||||
|
|
||||||
|
if r.Error != nil || !aws.BoolValue(r.Retryable) {
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.prepareRetry(); err != nil {
|
||||||
|
r.Error = err
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) prepareRetry() error {
|
||||||
|
if r.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) {
|
||||||
|
r.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d",
|
||||||
|
r.ClientInfo.ServiceName, r.Operation.Name, r.RetryCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The previous http.Request will have a reference to the r.Body
|
||||||
|
// and the HTTP Client's Transport may still be reading from
|
||||||
|
// the request's body even though the Client's Do returned.
|
||||||
|
r.HTTPRequest = copyHTTPRequest(r.HTTPRequest, nil)
|
||||||
|
r.ResetBody()
|
||||||
|
if err := r.Error; err != nil {
|
||||||
|
return awserr.New(ErrCodeSerialization,
|
||||||
|
"failed to prepare body for retry", err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closing response body to ensure that no response body is leaked
|
||||||
|
// between retry attempts.
|
||||||
|
if r.HTTPResponse != nil && r.HTTPResponse.Body != nil {
|
||||||
|
r.HTTPResponse.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) sendRequest() (sendErr error) {
|
||||||
|
defer r.Handlers.CompleteAttempt.Run(r)
|
||||||
|
|
||||||
|
r.Retryable = nil
|
||||||
|
r.Handlers.Send.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
debugLogReqError(r, "Send Request",
|
||||||
|
fmtAttemptCount(r.RetryCount, r.MaxRetries()),
|
||||||
|
r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Handlers.UnmarshalMeta.Run(r)
|
||||||
|
r.Handlers.ValidateResponse.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
r.Handlers.UnmarshalError.Run(r)
|
||||||
|
debugLogReqError(r, "Validate Response",
|
||||||
|
fmtAttemptCount(r.RetryCount, r.MaxRetries()),
|
||||||
|
r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Handlers.Unmarshal.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
debugLogReqError(r, "Unmarshal Response",
|
||||||
|
fmtAttemptCount(r.RetryCount, r.MaxRetries()),
|
||||||
|
r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy will copy a request which will allow for local manipulation of the
|
||||||
|
// request.
|
||||||
|
func (r *Request) copy() *Request {
|
||||||
|
req := &Request{}
|
||||||
|
*req = *r
|
||||||
|
req.Handlers = r.Handlers.Copy()
|
||||||
|
op := *r.Operation
|
||||||
|
req.Operation = &op
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddToUserAgent adds the string to the end of the request's current user agent.
|
||||||
|
func AddToUserAgent(r *Request, s string) {
|
||||||
|
curUA := r.HTTPRequest.Header.Get("User-Agent")
|
||||||
|
if len(curUA) > 0 {
|
||||||
|
s = curUA + " " + s
|
||||||
|
}
|
||||||
|
r.HTTPRequest.Header.Set("User-Agent", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SanitizeHostForHeader removes default port from host and updates request.Host
|
||||||
|
func SanitizeHostForHeader(r *http.Request) {
|
||||||
|
host := getHost(r)
|
||||||
|
port := portOnly(host)
|
||||||
|
if port != "" && isDefaultPort(r.URL.Scheme, port) {
|
||||||
|
r.Host = stripPort(host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns host from request
|
||||||
|
func getHost(r *http.Request) string {
|
||||||
|
if r.Host != "" {
|
||||||
|
return r.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.URL == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.URL.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hostname returns u.Host, without any port number.
|
||||||
|
//
|
||||||
|
// If Host is an IPv6 literal with a port number, Hostname returns the
|
||||||
|
// IPv6 literal without the square brackets. IPv6 literals may include
|
||||||
|
// a zone identifier.
|
||||||
|
//
|
||||||
|
// Copied from the Go 1.8 standard library (net/url)
|
||||||
|
func stripPort(hostport string) string {
|
||||||
|
colon := strings.IndexByte(hostport, ':')
|
||||||
|
if colon == -1 {
|
||||||
|
return hostport
|
||||||
|
}
|
||||||
|
if i := strings.IndexByte(hostport, ']'); i != -1 {
|
||||||
|
return strings.TrimPrefix(hostport[:i], "[")
|
||||||
|
}
|
||||||
|
return hostport[:colon]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Port returns the port part of u.Host, without the leading colon.
|
||||||
|
// If u.Host doesn't contain a port, Port returns an empty string.
|
||||||
|
//
|
||||||
|
// Copied from the Go 1.8 standard library (net/url)
|
||||||
|
func portOnly(hostport string) string {
|
||||||
|
colon := strings.IndexByte(hostport, ':')
|
||||||
|
if colon == -1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if i := strings.Index(hostport, "]:"); i != -1 {
|
||||||
|
return hostport[i+len("]:"):]
|
||||||
|
}
|
||||||
|
if strings.Contains(hostport, "]") {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return hostport[colon+len(":"):]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the specified URI is using the standard port
|
||||||
|
// (i.e. port 80 for HTTP URIs or 443 for HTTPS URIs)
|
||||||
|
func isDefaultPort(scheme, port string) bool {
|
||||||
|
if port == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
lowerCaseScheme := strings.ToLower(scheme)
|
||||||
|
if (lowerCaseScheme == "http" && port == "80") || (lowerCaseScheme == "https" && port == "443") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
40
vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7.go
generated
vendored
Normal file
40
vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//go:build !go1.8
|
||||||
|
// +build !go1.8
|
||||||
|
|
||||||
|
package request
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF
|
||||||
|
// and Close always returns nil. It can be used in an outgoing client
|
||||||
|
// request to explicitly signal that a request has zero bytes.
|
||||||
|
// An alternative, however, is to simply set Request.Body to nil.
|
||||||
|
//
|
||||||
|
// Copy of Go 1.8 NoBody type from net/http/http.go
|
||||||
|
type noBody struct{}
|
||||||
|
|
||||||
|
func (noBody) Read([]byte) (int, error) { return 0, io.EOF }
|
||||||
|
func (noBody) Close() error { return nil }
|
||||||
|
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil }
|
||||||
|
|
||||||
|
// NoBody is an empty reader that will trigger the Go HTTP client to not include
|
||||||
|
// and body in the HTTP request.
|
||||||
|
var NoBody = noBody{}
|
||||||
|
|
||||||
|
// ResetBody rewinds the request body back to its starting position, and
|
||||||
|
// sets the HTTP Request body reference. When the body is read prior
|
||||||
|
// to being sent in the HTTP request it will need to be rewound.
|
||||||
|
//
|
||||||
|
// ResetBody will automatically be called by the SDK's build handler, but if
|
||||||
|
// the request is being used directly ResetBody must be called before the request
|
||||||
|
// is Sent. SetStringBody, SetBufferBody, and SetReaderBody will automatically
|
||||||
|
// call ResetBody.
|
||||||
|
func (r *Request) ResetBody() {
|
||||||
|
body, err := r.getNextRequestBody()
|
||||||
|
if err != nil {
|
||||||
|
r.Error = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.HTTPRequest.Body = body
|
||||||
|
}
|
37
vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8.go
generated
vendored
Normal file
37
vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//go:build go1.8
|
||||||
|
// +build go1.8
|
||||||
|
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NoBody is a http.NoBody reader instructing Go HTTP client to not include
|
||||||
|
// and body in the HTTP request.
|
||||||
|
var NoBody = http.NoBody
|
||||||
|
|
||||||
|
// ResetBody rewinds the request body back to its starting position, and
|
||||||
|
// sets the HTTP Request body reference. When the body is read prior
|
||||||
|
// to being sent in the HTTP request it will need to be rewound.
|
||||||
|
//
|
||||||
|
// ResetBody will automatically be called by the SDK's build handler, but if
|
||||||
|
// the request is being used directly ResetBody must be called before the request
|
||||||
|
// is Sent. SetStringBody, SetBufferBody, and SetReaderBody will automatically
|
||||||
|
// call ResetBody.
|
||||||
|
//
|
||||||
|
// Will also set the Go 1.8's http.Request.GetBody member to allow retrying
|
||||||
|
// PUT/POST redirects.
|
||||||
|
func (r *Request) ResetBody() {
|
||||||
|
body, err := r.getNextRequestBody()
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New(ErrCodeSerialization,
|
||||||
|
"failed to reset request body", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.HTTPRequest.Body = body
|
||||||
|
r.HTTPRequest.GetBody = r.getNextRequestBody
|
||||||
|
}
|
15
vendor/github.com/aws/aws-sdk-go/aws/request/request_context.go
generated
vendored
Normal file
15
vendor/github.com/aws/aws-sdk-go/aws/request/request_context.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//go:build go1.7
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package request
|
||||||
|
|
||||||
|
import "github.com/aws/aws-sdk-go/aws"
|
||||||
|
|
||||||
|
// setContext updates the Request to use the passed in context for cancellation.
|
||||||
|
// Context will also be used for request retry delay.
|
||||||
|
//
|
||||||
|
// Creates shallow copy of the http.Request with the WithContext method.
|
||||||
|
func setRequestContext(r *Request, ctx aws.Context) {
|
||||||
|
r.context = ctx
|
||||||
|
r.HTTPRequest = r.HTTPRequest.WithContext(ctx)
|
||||||
|
}
|
15
vendor/github.com/aws/aws-sdk-go/aws/request/request_context_1_6.go
generated
vendored
Normal file
15
vendor/github.com/aws/aws-sdk-go/aws/request/request_context_1_6.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//go:build !go1.7
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package request
|
||||||
|
|
||||||
|
import "github.com/aws/aws-sdk-go/aws"
|
||||||
|
|
||||||
|
// setContext updates the Request to use the passed in context for cancellation.
|
||||||
|
// Context will also be used for request retry delay.
|
||||||
|
//
|
||||||
|
// Creates shallow copy of the http.Request with the WithContext method.
|
||||||
|
func setRequestContext(r *Request, ctx aws.Context) {
|
||||||
|
r.context = ctx
|
||||||
|
r.HTTPRequest.Cancel = ctx.Done()
|
||||||
|
}
|
266
vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination.go
generated
vendored
Normal file
266
vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination.go
generated
vendored
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Pagination provides paginating of SDK API operations which are paginatable.
|
||||||
|
// Generally you should not use this type directly, but use the "Pages" API
|
||||||
|
// operations method to automatically perform pagination for you. Such as,
|
||||||
|
// "S3.ListObjectsPages", and "S3.ListObjectsPagesWithContext" methods.
|
||||||
|
//
|
||||||
|
// Pagination differs from a Paginator type in that pagination is the type that
|
||||||
|
// does the pagination between API operations, and Paginator defines the
|
||||||
|
// configuration that will be used per page request.
|
||||||
|
//
|
||||||
|
// for p.Next() {
|
||||||
|
// data := p.Page().(*s3.ListObjectsOutput)
|
||||||
|
// // process the page's data
|
||||||
|
// // ...
|
||||||
|
// // break out of loop to stop fetching additional pages
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return p.Err()
|
||||||
|
//
|
||||||
|
// See service client API operation Pages methods for examples how the SDK will
|
||||||
|
// use the Pagination type.
|
||||||
|
type Pagination struct {
|
||||||
|
// Function to return a Request value for each pagination request.
|
||||||
|
// Any configuration or handlers that need to be applied to the request
|
||||||
|
// prior to getting the next page should be done here before the request
|
||||||
|
// returned.
|
||||||
|
//
|
||||||
|
// NewRequest should always be built from the same API operations. It is
|
||||||
|
// undefined if different API operations are returned on subsequent calls.
|
||||||
|
NewRequest func() (*Request, error)
|
||||||
|
// EndPageOnSameToken, when enabled, will allow the paginator to stop on
|
||||||
|
// token that are the same as its previous tokens.
|
||||||
|
EndPageOnSameToken bool
|
||||||
|
|
||||||
|
started bool
|
||||||
|
prevTokens []interface{}
|
||||||
|
nextTokens []interface{}
|
||||||
|
|
||||||
|
err error
|
||||||
|
curPage interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasNextPage will return true if Pagination is able to determine that the API
|
||||||
|
// operation has additional pages. False will be returned if there are no more
|
||||||
|
// pages remaining.
|
||||||
|
//
|
||||||
|
// Will always return true if Next has not been called yet.
|
||||||
|
func (p *Pagination) HasNextPage() bool {
|
||||||
|
if !p.started {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
hasNextPage := len(p.nextTokens) != 0
|
||||||
|
if p.EndPageOnSameToken {
|
||||||
|
return hasNextPage && !awsutil.DeepEqual(p.nextTokens, p.prevTokens)
|
||||||
|
}
|
||||||
|
return hasNextPage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err returns the error Pagination encountered when retrieving the next page.
|
||||||
|
func (p *Pagination) Err() error {
|
||||||
|
return p.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page returns the current page. Page should only be called after a successful
|
||||||
|
// call to Next. It is undefined what Page will return if Page is called after
|
||||||
|
// Next returns false.
|
||||||
|
func (p *Pagination) Page() interface{} {
|
||||||
|
return p.curPage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next will attempt to retrieve the next page for the API operation. When a page
|
||||||
|
// is retrieved true will be returned. If the page cannot be retrieved, or there
|
||||||
|
// are no more pages false will be returned.
|
||||||
|
//
|
||||||
|
// Use the Page method to retrieve the current page data. The data will need
|
||||||
|
// to be cast to the API operation's output type.
|
||||||
|
//
|
||||||
|
// Use the Err method to determine if an error occurred if Page returns false.
|
||||||
|
func (p *Pagination) Next() bool {
|
||||||
|
if !p.HasNextPage() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := p.NewRequest()
|
||||||
|
if err != nil {
|
||||||
|
p.err = err
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.started {
|
||||||
|
for i, intok := range req.Operation.InputTokens {
|
||||||
|
awsutil.SetValueAtPath(req.Params, intok, p.nextTokens[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.started = true
|
||||||
|
|
||||||
|
err = req.Send()
|
||||||
|
if err != nil {
|
||||||
|
p.err = err
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
p.prevTokens = p.nextTokens
|
||||||
|
p.nextTokens = req.nextPageTokens()
|
||||||
|
p.curPage = req.Data
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Paginator is the configuration data that defines how an API operation
|
||||||
|
// should be paginated. This type is used by the API service models to define
|
||||||
|
// the generated pagination config for service APIs.
|
||||||
|
//
|
||||||
|
// The Pagination type is what provides iterating between pages of an API. It
|
||||||
|
// is only used to store the token metadata the SDK should use for performing
|
||||||
|
// pagination.
|
||||||
|
type Paginator struct {
|
||||||
|
InputTokens []string
|
||||||
|
OutputTokens []string
|
||||||
|
LimitToken string
|
||||||
|
TruncationToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
// nextPageTokens returns the tokens to use when asking for the next page of data.
|
||||||
|
func (r *Request) nextPageTokens() []interface{} {
|
||||||
|
if r.Operation.Paginator == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if r.Operation.TruncationToken != "" {
|
||||||
|
tr, _ := awsutil.ValuesAtPath(r.Data, r.Operation.TruncationToken)
|
||||||
|
if len(tr) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := tr[0].(type) {
|
||||||
|
case *bool:
|
||||||
|
if !aws.BoolValue(v) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case bool:
|
||||||
|
if !v {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens := []interface{}{}
|
||||||
|
tokenAdded := false
|
||||||
|
for _, outToken := range r.Operation.OutputTokens {
|
||||||
|
vs, _ := awsutil.ValuesAtPath(r.Data, outToken)
|
||||||
|
if len(vs) == 0 {
|
||||||
|
tokens = append(tokens, nil)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v := vs[0]
|
||||||
|
|
||||||
|
switch tv := v.(type) {
|
||||||
|
case *string:
|
||||||
|
if len(aws.StringValue(tv)) == 0 {
|
||||||
|
tokens = append(tokens, nil)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
if len(tv) == 0 {
|
||||||
|
tokens = append(tokens, nil)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenAdded = true
|
||||||
|
tokens = append(tokens, v)
|
||||||
|
}
|
||||||
|
if !tokenAdded {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a deprecated item is only logged once instead of each time its used.
|
||||||
|
func logDeprecatedf(logger aws.Logger, flag *int32, msg string) {
|
||||||
|
if logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if atomic.CompareAndSwapInt32(flag, 0, 1) {
|
||||||
|
logger.Log(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
logDeprecatedHasNextPage int32
|
||||||
|
logDeprecatedNextPage int32
|
||||||
|
logDeprecatedEachPage int32
|
||||||
|
)
|
||||||
|
|
||||||
|
// HasNextPage returns true if this request has more pages of data available.
|
||||||
|
//
|
||||||
|
// Deprecated Use Pagination type for configurable pagination of API operations
|
||||||
|
func (r *Request) HasNextPage() bool {
|
||||||
|
logDeprecatedf(r.Config.Logger, &logDeprecatedHasNextPage,
|
||||||
|
"Request.HasNextPage deprecated. Use Pagination type for configurable pagination of API operations")
|
||||||
|
|
||||||
|
return len(r.nextPageTokens()) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPage returns a new Request that can be executed to return the next
|
||||||
|
// page of result data. Call .Send() on this request to execute it.
|
||||||
|
//
|
||||||
|
// Deprecated Use Pagination type for configurable pagination of API operations
|
||||||
|
func (r *Request) NextPage() *Request {
|
||||||
|
logDeprecatedf(r.Config.Logger, &logDeprecatedNextPage,
|
||||||
|
"Request.NextPage deprecated. Use Pagination type for configurable pagination of API operations")
|
||||||
|
|
||||||
|
tokens := r.nextPageTokens()
|
||||||
|
if len(tokens) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
|
||||||
|
nr := New(r.Config, r.ClientInfo, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data)
|
||||||
|
for i, intok := range nr.Operation.InputTokens {
|
||||||
|
awsutil.SetValueAtPath(nr.Params, intok, tokens[i])
|
||||||
|
}
|
||||||
|
return nr
|
||||||
|
}
|
||||||
|
|
||||||
|
// EachPage iterates over each page of a paginated request object. The fn
|
||||||
|
// parameter should be a function with the following sample signature:
|
||||||
|
//
|
||||||
|
// func(page *T, lastPage bool) bool {
|
||||||
|
// return true // return false to stop iterating
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Where "T" is the structure type matching the output structure of the given
|
||||||
|
// operation. For example, a request object generated by
|
||||||
|
// DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput
|
||||||
|
// as the structure "T". The lastPage value represents whether the page is
|
||||||
|
// the last page of data or not. The return value of this function should
|
||||||
|
// return true to keep iterating or false to stop.
|
||||||
|
//
|
||||||
|
// Deprecated Use Pagination type for configurable pagination of API operations
|
||||||
|
func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
|
||||||
|
logDeprecatedf(r.Config.Logger, &logDeprecatedEachPage,
|
||||||
|
"Request.EachPage deprecated. Use Pagination type for configurable pagination of API operations")
|
||||||
|
|
||||||
|
for page := r; page != nil; page = page.NextPage() {
|
||||||
|
if err := page.Send(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if getNextPage := fn(page.Data, !page.HasNextPage()); !getNextPage {
|
||||||
|
return page.Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
309
vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go
generated
vendored
Normal file
309
vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go
generated
vendored
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Retryer provides the interface drive the SDK's request retry behavior. The
|
||||||
|
// Retryer implementation is responsible for implementing exponential backoff,
|
||||||
|
// and determine if a request API error should be retried.
|
||||||
|
//
|
||||||
|
// client.DefaultRetryer is the SDK's default implementation of the Retryer. It
|
||||||
|
// uses the Request.IsErrorRetryable and Request.IsErrorThrottle methods to
|
||||||
|
// determine if the request is retried.
|
||||||
|
type Retryer interface {
|
||||||
|
// RetryRules return the retry delay that should be used by the SDK before
|
||||||
|
// making another request attempt for the failed request.
|
||||||
|
RetryRules(*Request) time.Duration
|
||||||
|
|
||||||
|
// ShouldRetry returns if the failed request is retryable.
|
||||||
|
//
|
||||||
|
// Implementations may consider request attempt count when determining if a
|
||||||
|
// request is retryable, but the SDK will use MaxRetries to limit the
|
||||||
|
// number of attempts a request are made.
|
||||||
|
ShouldRetry(*Request) bool
|
||||||
|
|
||||||
|
// MaxRetries is the number of times a request may be retried before
|
||||||
|
// failing.
|
||||||
|
MaxRetries() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRetryer sets a Retryer value to the given Config returning the Config
|
||||||
|
// value for chaining. The value must not be nil.
|
||||||
|
func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
|
||||||
|
if retryer == nil {
|
||||||
|
if cfg.Logger != nil {
|
||||||
|
cfg.Logger.Log("ERROR: Request.WithRetryer called with nil retryer. Replacing with retry disabled Retryer.")
|
||||||
|
}
|
||||||
|
retryer = noOpRetryer{}
|
||||||
|
}
|
||||||
|
cfg.Retryer = retryer
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// noOpRetryer is a internal no op retryer used when a request is created
|
||||||
|
// without a retryer.
|
||||||
|
//
|
||||||
|
// Provides a retryer that performs no retries.
|
||||||
|
// It should be used when we do not want retries to be performed.
|
||||||
|
type noOpRetryer struct{}
|
||||||
|
|
||||||
|
// MaxRetries returns the number of maximum returns the service will use to make
|
||||||
|
// an individual API; For NoOpRetryer the MaxRetries will always be zero.
|
||||||
|
func (d noOpRetryer) MaxRetries() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldRetry will always return false for NoOpRetryer, as it should never retry.
|
||||||
|
func (d noOpRetryer) ShouldRetry(_ *Request) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetryRules returns the delay duration before retrying this request again;
|
||||||
|
// since NoOpRetryer does not retry, RetryRules always returns 0.
|
||||||
|
func (d noOpRetryer) RetryRules(_ *Request) time.Duration {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// retryableCodes is a collection of service response codes which are retry-able
|
||||||
|
// without any further action.
|
||||||
|
var retryableCodes = map[string]struct{}{
|
||||||
|
ErrCodeRequestError: {},
|
||||||
|
"RequestTimeout": {},
|
||||||
|
ErrCodeResponseTimeout: {},
|
||||||
|
"RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
var throttleCodes = map[string]struct{}{
|
||||||
|
"ProvisionedThroughputExceededException": {},
|
||||||
|
"ThrottledException": {}, // SNS, XRay, ResourceGroupsTagging API
|
||||||
|
"Throttling": {},
|
||||||
|
"ThrottlingException": {},
|
||||||
|
"RequestLimitExceeded": {},
|
||||||
|
"RequestThrottled": {},
|
||||||
|
"RequestThrottledException": {},
|
||||||
|
"TooManyRequestsException": {}, // Lambda functions
|
||||||
|
"PriorRequestNotComplete": {}, // Route53
|
||||||
|
"TransactionInProgressException": {},
|
||||||
|
"EC2ThrottledException": {}, // EC2
|
||||||
|
}
|
||||||
|
|
||||||
|
// credsExpiredCodes is a collection of error codes which signify the credentials
|
||||||
|
// need to be refreshed. Expired tokens require refreshing of credentials, and
|
||||||
|
// resigning before the request can be retried.
|
||||||
|
var credsExpiredCodes = map[string]struct{}{
|
||||||
|
"ExpiredToken": {},
|
||||||
|
"ExpiredTokenException": {},
|
||||||
|
"RequestExpired": {}, // EC2 Only
|
||||||
|
}
|
||||||
|
|
||||||
|
func isCodeThrottle(code string) bool {
|
||||||
|
_, ok := throttleCodes[code]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func isCodeRetryable(code string) bool {
|
||||||
|
if _, ok := retryableCodes[code]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return isCodeExpiredCreds(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isCodeExpiredCreds(code string) bool {
|
||||||
|
_, ok := credsExpiredCodes[code]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
var validParentCodes = map[string]struct{}{
|
||||||
|
ErrCodeSerialization: {},
|
||||||
|
ErrCodeRead: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNestedErrorRetryable(parentErr awserr.Error) bool {
|
||||||
|
if parentErr == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := validParentCodes[parentErr.Code()]; !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
err := parentErr.OrigErr()
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if aerr, ok := err.(awserr.Error); ok {
|
||||||
|
return isCodeRetryable(aerr.Code())
|
||||||
|
}
|
||||||
|
|
||||||
|
if t, ok := err.(temporary); ok {
|
||||||
|
return t.Temporary() || isErrConnectionReset(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return isErrConnectionReset(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrorRetryable returns whether the error is retryable, based on its Code.
|
||||||
|
// Returns false if error is nil.
|
||||||
|
func IsErrorRetryable(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return shouldRetryError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type temporary interface {
|
||||||
|
Temporary() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldRetryError(origErr error) bool {
|
||||||
|
switch err := origErr.(type) {
|
||||||
|
case awserr.Error:
|
||||||
|
if err.Code() == CanceledErrorCode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if isNestedErrorRetryable(err) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
origErr := err.OrigErr()
|
||||||
|
var shouldRetry bool
|
||||||
|
if origErr != nil {
|
||||||
|
shouldRetry = shouldRetryError(origErr)
|
||||||
|
if err.Code() == ErrCodeRequestError && !shouldRetry {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isCodeRetryable(err.Code()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return shouldRetry
|
||||||
|
|
||||||
|
case *url.Error:
|
||||||
|
if strings.Contains(err.Error(), "connection refused") {
|
||||||
|
// Refused connections should be retried as the service may not yet
|
||||||
|
// be running on the port. Go TCP dial considers refused
|
||||||
|
// connections as not temporary.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// *url.Error only implements Temporary after golang 1.6 but since
|
||||||
|
// url.Error only wraps the error:
|
||||||
|
return shouldRetryError(err.Err)
|
||||||
|
|
||||||
|
case temporary:
|
||||||
|
if netErr, ok := err.(*net.OpError); ok && netErr.Op == "dial" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// If the error is temporary, we want to allow continuation of the
|
||||||
|
// retry process
|
||||||
|
return err.Temporary() || isErrConnectionReset(origErr)
|
||||||
|
|
||||||
|
case nil:
|
||||||
|
// `awserr.Error.OrigErr()` can be nil, meaning there was an error but
|
||||||
|
// because we don't know the cause, it is marked as retryable. See
|
||||||
|
// TestRequest4xxUnretryable for an example.
|
||||||
|
return true
|
||||||
|
|
||||||
|
default:
|
||||||
|
switch err.Error() {
|
||||||
|
case "net/http: request canceled",
|
||||||
|
"net/http: request canceled while waiting for connection":
|
||||||
|
// known 1.5 error case when an http request is cancelled
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// here we don't know the error; so we allow a retry.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrorThrottle returns whether the error is to be throttled based on its code.
|
||||||
|
// Returns false if error is nil.
|
||||||
|
func IsErrorThrottle(err error) bool {
|
||||||
|
if aerr, ok := err.(awserr.Error); ok && aerr != nil {
|
||||||
|
return isCodeThrottle(aerr.Code())
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrorExpiredCreds returns whether the error code is a credential expiry
|
||||||
|
// error. Returns false if error is nil.
|
||||||
|
func IsErrorExpiredCreds(err error) bool {
|
||||||
|
if aerr, ok := err.(awserr.Error); ok && aerr != nil {
|
||||||
|
return isCodeExpiredCreds(aerr.Code())
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrorRetryable returns whether the error is retryable, based on its Code.
|
||||||
|
// Returns false if the request has no Error set.
|
||||||
|
//
|
||||||
|
// Alias for the utility function IsErrorRetryable
|
||||||
|
func (r *Request) IsErrorRetryable() bool {
|
||||||
|
if isErrCode(r.Error, r.RetryErrorCodes) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP response status code 501 should not be retried.
|
||||||
|
// 501 represents Not Implemented which means the request method is not
|
||||||
|
// supported by the server and cannot be handled.
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
// HTTP response status code 500 represents internal server error and
|
||||||
|
// should be retried without any throttle.
|
||||||
|
if r.HTTPResponse.StatusCode == 500 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IsErrorRetryable(r.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrorThrottle returns whether the error is to be throttled based on its
|
||||||
|
// code. Returns false if the request has no Error set.
|
||||||
|
//
|
||||||
|
// Alias for the utility function IsErrorThrottle
|
||||||
|
func (r *Request) IsErrorThrottle() bool {
|
||||||
|
if isErrCode(r.Error, r.ThrottleErrorCodes) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
switch r.HTTPResponse.StatusCode {
|
||||||
|
case
|
||||||
|
429, // error caused due to too many requests
|
||||||
|
502, // Bad Gateway error should be throttled
|
||||||
|
503, // caused when service is unavailable
|
||||||
|
504: // error occurred due to gateway timeout
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsErrorThrottle(r.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isErrCode(err error, codes []string) bool {
|
||||||
|
if aerr, ok := err.(awserr.Error); ok && aerr != nil {
|
||||||
|
for _, code := range codes {
|
||||||
|
if code == aerr.Code() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrorExpired returns whether the error code is a credential expiry error.
|
||||||
|
// Returns false if the request has no Error set.
|
||||||
|
//
|
||||||
|
// Alias for the utility function IsErrorExpiredCreds
|
||||||
|
func (r *Request) IsErrorExpired() bool {
|
||||||
|
return IsErrorExpiredCreds(r.Error)
|
||||||
|
}
|
94
vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer.go
generated
vendored
Normal file
94
vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
var timeoutErr = awserr.New(
|
||||||
|
ErrCodeResponseTimeout,
|
||||||
|
"read on body has reached the timeout limit",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
type readResult struct {
|
||||||
|
n int
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// timeoutReadCloser will handle body reads that take too long.
|
||||||
|
// We will return a ErrReadTimeout error if a timeout occurs.
|
||||||
|
type timeoutReadCloser struct {
|
||||||
|
reader io.ReadCloser
|
||||||
|
duration time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read will spin off a goroutine to call the reader's Read method. We will
|
||||||
|
// select on the timer's channel or the read's channel. Whoever completes first
|
||||||
|
// will be returned.
|
||||||
|
func (r *timeoutReadCloser) Read(b []byte) (int, error) {
|
||||||
|
timer := time.NewTimer(r.duration)
|
||||||
|
c := make(chan readResult, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
n, err := r.reader.Read(b)
|
||||||
|
timer.Stop()
|
||||||
|
c <- readResult{n: n, err: err}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case data := <-c:
|
||||||
|
return data.n, data.err
|
||||||
|
case <-timer.C:
|
||||||
|
return 0, timeoutErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *timeoutReadCloser) Close() error {
|
||||||
|
return r.reader.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// HandlerResponseTimeout is what we use to signify the name of the
|
||||||
|
// response timeout handler.
|
||||||
|
HandlerResponseTimeout = "ResponseTimeoutHandler"
|
||||||
|
)
|
||||||
|
|
||||||
|
// adaptToResponseTimeoutError is a handler that will replace any top level error
|
||||||
|
// to a ErrCodeResponseTimeout, if its child is that.
|
||||||
|
func adaptToResponseTimeoutError(req *Request) {
|
||||||
|
if err, ok := req.Error.(awserr.Error); ok {
|
||||||
|
aerr, ok := err.OrigErr().(awserr.Error)
|
||||||
|
if ok && aerr.Code() == ErrCodeResponseTimeout {
|
||||||
|
req.Error = aerr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithResponseReadTimeout is a request option that will wrap the body in a timeout read closer.
|
||||||
|
// This will allow for per read timeouts. If a timeout occurred, we will return the
|
||||||
|
// ErrCodeResponseTimeout.
|
||||||
|
//
|
||||||
|
// svc.PutObjectWithContext(ctx, params, request.WithTimeoutReadCloser(30 * time.Second)
|
||||||
|
func WithResponseReadTimeout(duration time.Duration) Option {
|
||||||
|
return func(r *Request) {
|
||||||
|
|
||||||
|
var timeoutHandler = NamedHandler{
|
||||||
|
HandlerResponseTimeout,
|
||||||
|
func(req *Request) {
|
||||||
|
req.HTTPResponse.Body = &timeoutReadCloser{
|
||||||
|
reader: req.HTTPResponse.Body,
|
||||||
|
duration: duration,
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
// remove the handler so we are not stomping over any new durations.
|
||||||
|
r.Handlers.Send.RemoveByName(HandlerResponseTimeout)
|
||||||
|
r.Handlers.Send.PushBackNamed(timeoutHandler)
|
||||||
|
|
||||||
|
r.Handlers.Unmarshal.PushBack(adaptToResponseTimeoutError)
|
||||||
|
r.Handlers.UnmarshalError.PushBack(adaptToResponseTimeoutError)
|
||||||
|
}
|
||||||
|
}
|
286
vendor/github.com/aws/aws-sdk-go/aws/request/validation.go
generated
vendored
Normal file
286
vendor/github.com/aws/aws-sdk-go/aws/request/validation.go
generated
vendored
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// InvalidParameterErrCode is the error code for invalid parameters errors
|
||||||
|
InvalidParameterErrCode = "InvalidParameter"
|
||||||
|
// ParamRequiredErrCode is the error code for required parameter errors
|
||||||
|
ParamRequiredErrCode = "ParamRequiredError"
|
||||||
|
// ParamMinValueErrCode is the error code for fields with too low of a
|
||||||
|
// number value.
|
||||||
|
ParamMinValueErrCode = "ParamMinValueError"
|
||||||
|
// ParamMinLenErrCode is the error code for fields without enough elements.
|
||||||
|
ParamMinLenErrCode = "ParamMinLenError"
|
||||||
|
// ParamMaxLenErrCode is the error code for value being too long.
|
||||||
|
ParamMaxLenErrCode = "ParamMaxLenError"
|
||||||
|
|
||||||
|
// ParamFormatErrCode is the error code for a field with invalid
|
||||||
|
// format or characters.
|
||||||
|
ParamFormatErrCode = "ParamFormatInvalidError"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Validator provides a way for types to perform validation logic on their
|
||||||
|
// input values that external code can use to determine if a type's values
|
||||||
|
// are valid.
|
||||||
|
type Validator interface {
|
||||||
|
Validate() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ErrInvalidParams provides wrapping of invalid parameter errors found when
|
||||||
|
// validating API operation input parameters.
|
||||||
|
type ErrInvalidParams struct {
|
||||||
|
// Context is the base context of the invalid parameter group.
|
||||||
|
Context string
|
||||||
|
errs []ErrInvalidParam
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds a new invalid parameter error to the collection of invalid
|
||||||
|
// parameters. The context of the invalid parameter will be updated to reflect
|
||||||
|
// this collection.
|
||||||
|
func (e *ErrInvalidParams) Add(err ErrInvalidParam) {
|
||||||
|
err.SetContext(e.Context)
|
||||||
|
e.errs = append(e.errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNested adds the invalid parameter errors from another ErrInvalidParams
|
||||||
|
// value into this collection. The nested errors will have their nested context
|
||||||
|
// updated and base context to reflect the merging.
|
||||||
|
//
|
||||||
|
// Use for nested validations errors.
|
||||||
|
func (e *ErrInvalidParams) AddNested(nestedCtx string, nested ErrInvalidParams) {
|
||||||
|
for _, err := range nested.errs {
|
||||||
|
err.SetContext(e.Context)
|
||||||
|
err.AddNestedContext(nestedCtx)
|
||||||
|
e.errs = append(e.errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of invalid parameter errors
|
||||||
|
func (e ErrInvalidParams) Len() int {
|
||||||
|
return len(e.errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code returns the code of the error
|
||||||
|
func (e ErrInvalidParams) Code() string {
|
||||||
|
return InvalidParameterErrCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message returns the message of the error
|
||||||
|
func (e ErrInvalidParams) Message() string {
|
||||||
|
return fmt.Sprintf("%d validation error(s) found.", len(e.errs))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns the string formatted form of the invalid parameters.
|
||||||
|
func (e ErrInvalidParams) Error() string {
|
||||||
|
w := &bytes.Buffer{}
|
||||||
|
fmt.Fprintf(w, "%s: %s\n", e.Code(), e.Message())
|
||||||
|
|
||||||
|
for _, err := range e.errs {
|
||||||
|
fmt.Fprintf(w, "- %s\n", err.Message())
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrigErr returns the invalid parameters as a awserr.BatchedErrors value
|
||||||
|
func (e ErrInvalidParams) OrigErr() error {
|
||||||
|
return awserr.NewBatchError(
|
||||||
|
InvalidParameterErrCode, e.Message(), e.OrigErrs())
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrigErrs returns a slice of the invalid parameters
|
||||||
|
func (e ErrInvalidParams) OrigErrs() []error {
|
||||||
|
errs := make([]error, len(e.errs))
|
||||||
|
for i := 0; i < len(errs); i++ {
|
||||||
|
errs[i] = e.errs[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ErrInvalidParam represents an invalid parameter error type.
|
||||||
|
type ErrInvalidParam interface {
|
||||||
|
awserr.Error
|
||||||
|
|
||||||
|
// Field name the error occurred on.
|
||||||
|
Field() string
|
||||||
|
|
||||||
|
// SetContext updates the context of the error.
|
||||||
|
SetContext(string)
|
||||||
|
|
||||||
|
// AddNestedContext updates the error's context to include a nested level.
|
||||||
|
AddNestedContext(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type errInvalidParam struct {
|
||||||
|
context string
|
||||||
|
nestedContext string
|
||||||
|
field string
|
||||||
|
code string
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code returns the error code for the type of invalid parameter.
|
||||||
|
func (e *errInvalidParam) Code() string {
|
||||||
|
return e.code
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message returns the reason the parameter was invalid, and its context.
|
||||||
|
func (e *errInvalidParam) Message() string {
|
||||||
|
return fmt.Sprintf("%s, %s.", e.msg, e.Field())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns the string version of the invalid parameter error.
|
||||||
|
func (e *errInvalidParam) Error() string {
|
||||||
|
return fmt.Sprintf("%s: %s", e.code, e.Message())
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrigErr returns nil, Implemented for awserr.Error interface.
|
||||||
|
func (e *errInvalidParam) OrigErr() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field Returns the field and context the error occurred.
|
||||||
|
func (e *errInvalidParam) Field() string {
|
||||||
|
field := e.context
|
||||||
|
if len(field) > 0 {
|
||||||
|
field += "."
|
||||||
|
}
|
||||||
|
if len(e.nestedContext) > 0 {
|
||||||
|
field += fmt.Sprintf("%s.", e.nestedContext)
|
||||||
|
}
|
||||||
|
field += e.field
|
||||||
|
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContext updates the base context of the error.
|
||||||
|
func (e *errInvalidParam) SetContext(ctx string) {
|
||||||
|
e.context = ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNestedContext prepends a context to the field's path.
|
||||||
|
func (e *errInvalidParam) AddNestedContext(ctx string) {
|
||||||
|
if len(e.nestedContext) == 0 {
|
||||||
|
e.nestedContext = ctx
|
||||||
|
} else {
|
||||||
|
e.nestedContext = fmt.Sprintf("%s.%s", ctx, e.nestedContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ErrParamRequired represents an required parameter error.
|
||||||
|
type ErrParamRequired struct {
|
||||||
|
errInvalidParam
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrParamRequired creates a new required parameter error.
|
||||||
|
func NewErrParamRequired(field string) *ErrParamRequired {
|
||||||
|
return &ErrParamRequired{
|
||||||
|
errInvalidParam{
|
||||||
|
code: ParamRequiredErrCode,
|
||||||
|
field: field,
|
||||||
|
msg: fmt.Sprintf("missing required field"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ErrParamMinValue represents a minimum value parameter error.
|
||||||
|
type ErrParamMinValue struct {
|
||||||
|
errInvalidParam
|
||||||
|
min float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrParamMinValue creates a new minimum value parameter error.
|
||||||
|
func NewErrParamMinValue(field string, min float64) *ErrParamMinValue {
|
||||||
|
return &ErrParamMinValue{
|
||||||
|
errInvalidParam: errInvalidParam{
|
||||||
|
code: ParamMinValueErrCode,
|
||||||
|
field: field,
|
||||||
|
msg: fmt.Sprintf("minimum field value of %v", min),
|
||||||
|
},
|
||||||
|
min: min,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinValue returns the field's require minimum value.
|
||||||
|
//
|
||||||
|
// float64 is returned for both int and float min values.
|
||||||
|
func (e *ErrParamMinValue) MinValue() float64 {
|
||||||
|
return e.min
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ErrParamMinLen represents a minimum length parameter error.
|
||||||
|
type ErrParamMinLen struct {
|
||||||
|
errInvalidParam
|
||||||
|
min int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrParamMinLen creates a new minimum length parameter error.
|
||||||
|
func NewErrParamMinLen(field string, min int) *ErrParamMinLen {
|
||||||
|
return &ErrParamMinLen{
|
||||||
|
errInvalidParam: errInvalidParam{
|
||||||
|
code: ParamMinLenErrCode,
|
||||||
|
field: field,
|
||||||
|
msg: fmt.Sprintf("minimum field size of %v", min),
|
||||||
|
},
|
||||||
|
min: min,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinLen returns the field's required minimum length.
|
||||||
|
func (e *ErrParamMinLen) MinLen() int {
|
||||||
|
return e.min
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ErrParamMaxLen represents a maximum length parameter error.
|
||||||
|
type ErrParamMaxLen struct {
|
||||||
|
errInvalidParam
|
||||||
|
max int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrParamMaxLen creates a new maximum length parameter error.
|
||||||
|
func NewErrParamMaxLen(field string, max int, value string) *ErrParamMaxLen {
|
||||||
|
return &ErrParamMaxLen{
|
||||||
|
errInvalidParam: errInvalidParam{
|
||||||
|
code: ParamMaxLenErrCode,
|
||||||
|
field: field,
|
||||||
|
msg: fmt.Sprintf("maximum size of %v, %v", max, value),
|
||||||
|
},
|
||||||
|
max: max,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaxLen returns the field's required minimum length.
|
||||||
|
func (e *ErrParamMaxLen) MaxLen() int {
|
||||||
|
return e.max
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ErrParamFormat represents a invalid format parameter error.
|
||||||
|
type ErrParamFormat struct {
|
||||||
|
errInvalidParam
|
||||||
|
format string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrParamFormat creates a new invalid format parameter error.
|
||||||
|
func NewErrParamFormat(field string, format, value string) *ErrParamFormat {
|
||||||
|
return &ErrParamFormat{
|
||||||
|
errInvalidParam: errInvalidParam{
|
||||||
|
code: ParamFormatErrCode,
|
||||||
|
field: field,
|
||||||
|
msg: fmt.Sprintf("format %v, %v", format, value),
|
||||||
|
},
|
||||||
|
format: format,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format returns the field's required format.
|
||||||
|
func (e *ErrParamFormat) Format() string {
|
||||||
|
return e.format
|
||||||
|
}
|
295
vendor/github.com/aws/aws-sdk-go/aws/request/waiter.go
generated
vendored
Normal file
295
vendor/github.com/aws/aws-sdk-go/aws/request/waiter.go
generated
vendored
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WaiterResourceNotReadyErrorCode is the error code returned by a waiter when
|
||||||
|
// the waiter's max attempts have been exhausted.
|
||||||
|
const WaiterResourceNotReadyErrorCode = "ResourceNotReady"
|
||||||
|
|
||||||
|
// A WaiterOption is a function that will update the Waiter value's fields to
|
||||||
|
// configure the waiter.
|
||||||
|
type WaiterOption func(*Waiter)
|
||||||
|
|
||||||
|
// WithWaiterMaxAttempts returns the maximum number of times the waiter should
|
||||||
|
// attempt to check the resource for the target state.
|
||||||
|
func WithWaiterMaxAttempts(max int) WaiterOption {
|
||||||
|
return func(w *Waiter) {
|
||||||
|
w.MaxAttempts = max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaiterDelay will return a delay the waiter should pause between attempts to
|
||||||
|
// check the resource state. The passed in attempt is the number of times the
|
||||||
|
// Waiter has checked the resource state.
|
||||||
|
//
|
||||||
|
// Attempt is the number of attempts the Waiter has made checking the resource
|
||||||
|
// state.
|
||||||
|
type WaiterDelay func(attempt int) time.Duration
|
||||||
|
|
||||||
|
// ConstantWaiterDelay returns a WaiterDelay that will always return a constant
|
||||||
|
// delay the waiter should use between attempts. It ignores the number of
|
||||||
|
// attempts made.
|
||||||
|
func ConstantWaiterDelay(delay time.Duration) WaiterDelay {
|
||||||
|
return func(attempt int) time.Duration {
|
||||||
|
return delay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithWaiterDelay will set the Waiter to use the WaiterDelay passed in.
|
||||||
|
func WithWaiterDelay(delayer WaiterDelay) WaiterOption {
|
||||||
|
return func(w *Waiter) {
|
||||||
|
w.Delay = delayer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithWaiterLogger returns a waiter option to set the logger a waiter
|
||||||
|
// should use to log warnings and errors to.
|
||||||
|
func WithWaiterLogger(logger aws.Logger) WaiterOption {
|
||||||
|
return func(w *Waiter) {
|
||||||
|
w.Logger = logger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithWaiterRequestOptions returns a waiter option setting the request
|
||||||
|
// options for each request the waiter makes. Appends to waiter's request
|
||||||
|
// options already set.
|
||||||
|
func WithWaiterRequestOptions(opts ...Option) WaiterOption {
|
||||||
|
return func(w *Waiter) {
|
||||||
|
w.RequestOptions = append(w.RequestOptions, opts...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Waiter provides the functionality to perform a blocking call which will
|
||||||
|
// wait for a resource state to be satisfied by a service.
|
||||||
|
//
|
||||||
|
// This type should not be used directly. The API operations provided in the
|
||||||
|
// service packages prefixed with "WaitUntil" should be used instead.
|
||||||
|
type Waiter struct {
|
||||||
|
Name string
|
||||||
|
Acceptors []WaiterAcceptor
|
||||||
|
Logger aws.Logger
|
||||||
|
|
||||||
|
MaxAttempts int
|
||||||
|
Delay WaiterDelay
|
||||||
|
|
||||||
|
RequestOptions []Option
|
||||||
|
NewRequest func([]Option) (*Request, error)
|
||||||
|
SleepWithContext func(aws.Context, time.Duration) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyOptions updates the waiter with the list of waiter options provided.
|
||||||
|
func (w *Waiter) ApplyOptions(opts ...WaiterOption) {
|
||||||
|
for _, fn := range opts {
|
||||||
|
fn(w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaiterState are states the waiter uses based on WaiterAcceptor definitions
|
||||||
|
// to identify if the resource state the waiter is waiting on has occurred.
|
||||||
|
type WaiterState int
|
||||||
|
|
||||||
|
// String returns the string representation of the waiter state.
|
||||||
|
func (s WaiterState) String() string {
|
||||||
|
switch s {
|
||||||
|
case SuccessWaiterState:
|
||||||
|
return "success"
|
||||||
|
case FailureWaiterState:
|
||||||
|
return "failure"
|
||||||
|
case RetryWaiterState:
|
||||||
|
return "retry"
|
||||||
|
default:
|
||||||
|
return "unknown waiter state"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// States the waiter acceptors will use to identify target resource states.
|
||||||
|
const (
|
||||||
|
SuccessWaiterState WaiterState = iota // waiter successful
|
||||||
|
FailureWaiterState // waiter failed
|
||||||
|
RetryWaiterState // waiter needs to be retried
|
||||||
|
)
|
||||||
|
|
||||||
|
// WaiterMatchMode is the mode that the waiter will use to match the WaiterAcceptor
|
||||||
|
// definition's Expected attribute.
|
||||||
|
type WaiterMatchMode int
|
||||||
|
|
||||||
|
// Modes the waiter will use when inspecting API response to identify target
|
||||||
|
// resource states.
|
||||||
|
const (
|
||||||
|
PathAllWaiterMatch WaiterMatchMode = iota // match on all paths
|
||||||
|
PathWaiterMatch // match on specific path
|
||||||
|
PathAnyWaiterMatch // match on any path
|
||||||
|
PathListWaiterMatch // match on list of paths
|
||||||
|
StatusWaiterMatch // match on status code
|
||||||
|
ErrorWaiterMatch // match on error
|
||||||
|
)
|
||||||
|
|
||||||
|
// String returns the string representation of the waiter match mode.
|
||||||
|
func (m WaiterMatchMode) String() string {
|
||||||
|
switch m {
|
||||||
|
case PathAllWaiterMatch:
|
||||||
|
return "pathAll"
|
||||||
|
case PathWaiterMatch:
|
||||||
|
return "path"
|
||||||
|
case PathAnyWaiterMatch:
|
||||||
|
return "pathAny"
|
||||||
|
case PathListWaiterMatch:
|
||||||
|
return "pathList"
|
||||||
|
case StatusWaiterMatch:
|
||||||
|
return "status"
|
||||||
|
case ErrorWaiterMatch:
|
||||||
|
return "error"
|
||||||
|
default:
|
||||||
|
return "unknown waiter match mode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitWithContext will make requests for the API operation using NewRequest to
|
||||||
|
// build API requests. The request's response will be compared against the
|
||||||
|
// Waiter's Acceptors to determine the successful state of the resource the
|
||||||
|
// waiter is inspecting.
|
||||||
|
//
|
||||||
|
// The passed in context must not be nil. If it is nil a panic will occur. The
|
||||||
|
// Context will be used to cancel the waiter's pending requests and retry delays.
|
||||||
|
// Use aws.BackgroundContext if no context is available.
|
||||||
|
//
|
||||||
|
// The waiter will continue until the target state defined by the Acceptors,
|
||||||
|
// or the max attempts expires.
|
||||||
|
//
|
||||||
|
// Will return the WaiterResourceNotReadyErrorCode error code if the waiter's
|
||||||
|
// retryer ShouldRetry returns false. This normally will happen when the max
|
||||||
|
// wait attempts expires.
|
||||||
|
func (w Waiter) WaitWithContext(ctx aws.Context) error {
|
||||||
|
|
||||||
|
for attempt := 1; ; attempt++ {
|
||||||
|
req, err := w.NewRequest(w.RequestOptions)
|
||||||
|
if err != nil {
|
||||||
|
waiterLogf(w.Logger, "unable to create request %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Handlers.Build.PushBack(MakeAddToUserAgentFreeFormHandler("Waiter"))
|
||||||
|
err = req.Send()
|
||||||
|
|
||||||
|
// See if any of the acceptors match the request's response, or error
|
||||||
|
for _, a := range w.Acceptors {
|
||||||
|
if matched, matchErr := a.match(w.Name, w.Logger, req, err); matched {
|
||||||
|
return matchErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Waiter should only check the resource state MaxAttempts times
|
||||||
|
// This is here instead of in the for loop above to prevent delaying
|
||||||
|
// unnecessary when the waiter will not retry.
|
||||||
|
if attempt == w.MaxAttempts {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay to wait before inspecting the resource again
|
||||||
|
delay := w.Delay(attempt)
|
||||||
|
if sleepFn := req.Config.SleepDelay; sleepFn != nil {
|
||||||
|
// Support SleepDelay for backwards compatibility and testing
|
||||||
|
sleepFn(delay)
|
||||||
|
} else {
|
||||||
|
sleepCtxFn := w.SleepWithContext
|
||||||
|
if sleepCtxFn == nil {
|
||||||
|
sleepCtxFn = aws.SleepWithContext
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sleepCtxFn(ctx, delay); err != nil {
|
||||||
|
return awserr.New(CanceledErrorCode, "waiter context canceled", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return awserr.New(WaiterResourceNotReadyErrorCode, "exceeded wait attempts", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A WaiterAcceptor provides the information needed to wait for an API operation
|
||||||
|
// to complete.
|
||||||
|
type WaiterAcceptor struct {
|
||||||
|
State WaiterState
|
||||||
|
Matcher WaiterMatchMode
|
||||||
|
Argument string
|
||||||
|
Expected interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// match returns if the acceptor found a match with the passed in request
|
||||||
|
// or error. True is returned if the acceptor made a match, error is returned
|
||||||
|
// if there was an error attempting to perform the match.
|
||||||
|
func (a *WaiterAcceptor) match(name string, l aws.Logger, req *Request, err error) (bool, error) {
|
||||||
|
result := false
|
||||||
|
var vals []interface{}
|
||||||
|
|
||||||
|
switch a.Matcher {
|
||||||
|
case PathAllWaiterMatch, PathWaiterMatch:
|
||||||
|
// Require all matches to be equal for result to match
|
||||||
|
vals, _ = awsutil.ValuesAtPath(req.Data, a.Argument)
|
||||||
|
if len(vals) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result = true
|
||||||
|
for _, val := range vals {
|
||||||
|
if !awsutil.DeepEqual(val, a.Expected) {
|
||||||
|
result = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PathAnyWaiterMatch:
|
||||||
|
// Only a single match needs to equal for the result to match
|
||||||
|
vals, _ = awsutil.ValuesAtPath(req.Data, a.Argument)
|
||||||
|
for _, val := range vals {
|
||||||
|
if awsutil.DeepEqual(val, a.Expected) {
|
||||||
|
result = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PathListWaiterMatch:
|
||||||
|
// ignored matcher
|
||||||
|
case StatusWaiterMatch:
|
||||||
|
s := a.Expected.(int)
|
||||||
|
result = s == req.HTTPResponse.StatusCode
|
||||||
|
case ErrorWaiterMatch:
|
||||||
|
if aerr, ok := err.(awserr.Error); ok {
|
||||||
|
result = aerr.Code() == a.Expected.(string)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
waiterLogf(l, "WARNING: Waiter %s encountered unexpected matcher: %s",
|
||||||
|
name, a.Matcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !result {
|
||||||
|
// If there was no matching result found there is nothing more to do
|
||||||
|
// for this response, retry the request.
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch a.State {
|
||||||
|
case SuccessWaiterState:
|
||||||
|
// waiter completed
|
||||||
|
return true, nil
|
||||||
|
case FailureWaiterState:
|
||||||
|
// Waiter failure state triggered
|
||||||
|
return true, awserr.New(WaiterResourceNotReadyErrorCode,
|
||||||
|
"failed waiting for successful resource state", err)
|
||||||
|
case RetryWaiterState:
|
||||||
|
// clear the error and retry the operation
|
||||||
|
return false, nil
|
||||||
|
default:
|
||||||
|
waiterLogf(l, "WARNING: Waiter %s encountered unexpected state: %s",
|
||||||
|
name, a.State)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func waiterLogf(logger aws.Logger, msg string, args ...interface{}) {
|
||||||
|
if logger != nil {
|
||||||
|
logger.Log(fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
}
|
303
vendor/github.com/aws/aws-sdk-go/aws/session/credentials.go
generated
vendored
Normal file
303
vendor/github.com/aws/aws-sdk-go/aws/session/credentials.go
generated
vendored
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials/processcreds"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials/ssocreds"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/shareddefaults"
|
||||||
|
"github.com/aws/aws-sdk-go/service/sts"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CredentialsProviderOptions specifies additional options for configuring
|
||||||
|
// credentials providers.
|
||||||
|
type CredentialsProviderOptions struct {
|
||||||
|
// WebIdentityRoleProviderOptions configures a WebIdentityRoleProvider,
|
||||||
|
// such as setting its ExpiryWindow.
|
||||||
|
WebIdentityRoleProviderOptions func(*stscreds.WebIdentityRoleProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveCredentials(cfg *aws.Config,
|
||||||
|
envCfg envConfig, sharedCfg sharedConfig,
|
||||||
|
handlers request.Handlers,
|
||||||
|
sessOpts Options,
|
||||||
|
) (*credentials.Credentials, error) {
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(sessOpts.Profile) != 0:
|
||||||
|
// User explicitly provided an Profile in the session's configuration
|
||||||
|
// so load that profile from shared config first.
|
||||||
|
// Github(aws/aws-sdk-go#2727)
|
||||||
|
return resolveCredsFromProfile(cfg, envCfg, sharedCfg, handlers, sessOpts)
|
||||||
|
|
||||||
|
case envCfg.Creds.HasKeys():
|
||||||
|
// Environment credentials
|
||||||
|
return credentials.NewStaticCredentialsFromCreds(envCfg.Creds), nil
|
||||||
|
|
||||||
|
case len(envCfg.WebIdentityTokenFilePath) != 0:
|
||||||
|
// Web identity token from environment, RoleARN required to also be
|
||||||
|
// set.
|
||||||
|
return assumeWebIdentity(cfg, handlers,
|
||||||
|
envCfg.WebIdentityTokenFilePath,
|
||||||
|
envCfg.RoleARN,
|
||||||
|
envCfg.RoleSessionName,
|
||||||
|
sessOpts.CredentialsProviderOptions,
|
||||||
|
)
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Fallback to the "default" credential resolution chain.
|
||||||
|
return resolveCredsFromProfile(cfg, envCfg, sharedCfg, handlers, sessOpts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebIdentityEmptyRoleARNErr will occur if 'AWS_WEB_IDENTITY_TOKEN_FILE' was set but
|
||||||
|
// 'AWS_ROLE_ARN' was not set.
|
||||||
|
var WebIdentityEmptyRoleARNErr = awserr.New(stscreds.ErrCodeWebIdentity, "role ARN is not set", nil)
|
||||||
|
|
||||||
|
// WebIdentityEmptyTokenFilePathErr will occur if 'AWS_ROLE_ARN' was set but
|
||||||
|
// 'AWS_WEB_IDENTITY_TOKEN_FILE' was not set.
|
||||||
|
var WebIdentityEmptyTokenFilePathErr = awserr.New(stscreds.ErrCodeWebIdentity, "token file path is not set", nil)
|
||||||
|
|
||||||
|
func assumeWebIdentity(cfg *aws.Config, handlers request.Handlers,
|
||||||
|
filepath string,
|
||||||
|
roleARN, sessionName string,
|
||||||
|
credOptions *CredentialsProviderOptions,
|
||||||
|
) (*credentials.Credentials, error) {
|
||||||
|
|
||||||
|
if len(filepath) == 0 {
|
||||||
|
return nil, WebIdentityEmptyTokenFilePathErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(roleARN) == 0 {
|
||||||
|
return nil, WebIdentityEmptyRoleARNErr
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := sts.New(&Session{
|
||||||
|
Config: cfg,
|
||||||
|
Handlers: handlers.Copy(),
|
||||||
|
})
|
||||||
|
|
||||||
|
var optFns []func(*stscreds.WebIdentityRoleProvider)
|
||||||
|
if credOptions != nil && credOptions.WebIdentityRoleProviderOptions != nil {
|
||||||
|
optFns = append(optFns, credOptions.WebIdentityRoleProviderOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := stscreds.NewWebIdentityRoleProviderWithOptions(svc, roleARN, sessionName, stscreds.FetchTokenPath(filepath), optFns...)
|
||||||
|
return credentials.NewCredentials(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveCredsFromProfile(cfg *aws.Config,
|
||||||
|
envCfg envConfig, sharedCfg sharedConfig,
|
||||||
|
handlers request.Handlers,
|
||||||
|
sessOpts Options,
|
||||||
|
) (creds *credentials.Credentials, err error) {
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sharedCfg.SourceProfile != nil:
|
||||||
|
// Assume IAM role with credentials source from a different profile.
|
||||||
|
creds, err = resolveCredsFromProfile(cfg, envCfg,
|
||||||
|
*sharedCfg.SourceProfile, handlers, sessOpts,
|
||||||
|
)
|
||||||
|
|
||||||
|
case sharedCfg.Creds.HasKeys():
|
||||||
|
// Static Credentials from Shared Config/Credentials file.
|
||||||
|
creds = credentials.NewStaticCredentialsFromCreds(
|
||||||
|
sharedCfg.Creds,
|
||||||
|
)
|
||||||
|
|
||||||
|
case len(sharedCfg.CredentialSource) != 0:
|
||||||
|
creds, err = resolveCredsFromSource(cfg, envCfg,
|
||||||
|
sharedCfg, handlers, sessOpts,
|
||||||
|
)
|
||||||
|
|
||||||
|
case len(sharedCfg.WebIdentityTokenFile) != 0:
|
||||||
|
// Credentials from Assume Web Identity token require an IAM Role, and
|
||||||
|
// that roll will be assumed. May be wrapped with another assume role
|
||||||
|
// via SourceProfile.
|
||||||
|
return assumeWebIdentity(cfg, handlers,
|
||||||
|
sharedCfg.WebIdentityTokenFile,
|
||||||
|
sharedCfg.RoleARN,
|
||||||
|
sharedCfg.RoleSessionName,
|
||||||
|
sessOpts.CredentialsProviderOptions,
|
||||||
|
)
|
||||||
|
|
||||||
|
case sharedCfg.hasSSOConfiguration():
|
||||||
|
creds, err = resolveSSOCredentials(cfg, sharedCfg, handlers)
|
||||||
|
|
||||||
|
case len(sharedCfg.CredentialProcess) != 0:
|
||||||
|
// Get credentials from CredentialProcess
|
||||||
|
creds = processcreds.NewCredentials(sharedCfg.CredentialProcess)
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Fallback to default credentials provider, include mock errors for
|
||||||
|
// the credential chain so user can identify why credentials failed to
|
||||||
|
// be retrieved.
|
||||||
|
creds = credentials.NewCredentials(&credentials.ChainProvider{
|
||||||
|
VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors),
|
||||||
|
Providers: []credentials.Provider{
|
||||||
|
&credProviderError{
|
||||||
|
Err: awserr.New("EnvAccessKeyNotFound",
|
||||||
|
"failed to find credentials in the environment.", nil),
|
||||||
|
},
|
||||||
|
&credProviderError{
|
||||||
|
Err: awserr.New("SharedCredsLoad",
|
||||||
|
fmt.Sprintf("failed to load profile, %s.", envCfg.Profile), nil),
|
||||||
|
},
|
||||||
|
defaults.RemoteCredProvider(*cfg, handlers),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sharedCfg.RoleARN) > 0 {
|
||||||
|
cfgCp := *cfg
|
||||||
|
cfgCp.Credentials = creds
|
||||||
|
return credsFromAssumeRole(cfgCp, handlers, sharedCfg, sessOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return creds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveSSOCredentials(cfg *aws.Config, sharedCfg sharedConfig, handlers request.Handlers) (*credentials.Credentials, error) {
|
||||||
|
if err := sharedCfg.validateSSOConfiguration(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgCopy := cfg.Copy()
|
||||||
|
cfgCopy.Region = &sharedCfg.SSORegion
|
||||||
|
|
||||||
|
return ssocreds.NewCredentials(
|
||||||
|
&Session{
|
||||||
|
Config: cfgCopy,
|
||||||
|
Handlers: handlers.Copy(),
|
||||||
|
},
|
||||||
|
sharedCfg.SSOAccountID,
|
||||||
|
sharedCfg.SSORoleName,
|
||||||
|
sharedCfg.SSOStartURL,
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// valid credential source values
|
||||||
|
const (
|
||||||
|
credSourceEc2Metadata = "Ec2InstanceMetadata"
|
||||||
|
credSourceEnvironment = "Environment"
|
||||||
|
credSourceECSContainer = "EcsContainer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resolveCredsFromSource(cfg *aws.Config,
|
||||||
|
envCfg envConfig, sharedCfg sharedConfig,
|
||||||
|
handlers request.Handlers,
|
||||||
|
sessOpts Options,
|
||||||
|
) (creds *credentials.Credentials, err error) {
|
||||||
|
|
||||||
|
switch sharedCfg.CredentialSource {
|
||||||
|
case credSourceEc2Metadata:
|
||||||
|
p := defaults.RemoteCredProvider(*cfg, handlers)
|
||||||
|
creds = credentials.NewCredentials(p)
|
||||||
|
|
||||||
|
case credSourceEnvironment:
|
||||||
|
creds = credentials.NewStaticCredentialsFromCreds(envCfg.Creds)
|
||||||
|
|
||||||
|
case credSourceECSContainer:
|
||||||
|
if len(os.Getenv(shareddefaults.ECSCredsProviderEnvVar)) == 0 {
|
||||||
|
return nil, ErrSharedConfigECSContainerEnvVarEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
p := defaults.RemoteCredProvider(*cfg, handlers)
|
||||||
|
creds = credentials.NewCredentials(p)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, ErrSharedConfigInvalidCredSource
|
||||||
|
}
|
||||||
|
|
||||||
|
return creds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func credsFromAssumeRole(cfg aws.Config,
|
||||||
|
handlers request.Handlers,
|
||||||
|
sharedCfg sharedConfig,
|
||||||
|
sessOpts Options,
|
||||||
|
) (*credentials.Credentials, error) {
|
||||||
|
|
||||||
|
if len(sharedCfg.MFASerial) != 0 && sessOpts.AssumeRoleTokenProvider == nil {
|
||||||
|
// AssumeRole Token provider is required if doing Assume Role
|
||||||
|
// with MFA.
|
||||||
|
return nil, AssumeRoleTokenProviderNotSetError{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stscreds.NewCredentials(
|
||||||
|
&Session{
|
||||||
|
Config: &cfg,
|
||||||
|
Handlers: handlers.Copy(),
|
||||||
|
},
|
||||||
|
sharedCfg.RoleARN,
|
||||||
|
func(opt *stscreds.AssumeRoleProvider) {
|
||||||
|
opt.RoleSessionName = sharedCfg.RoleSessionName
|
||||||
|
|
||||||
|
if sessOpts.AssumeRoleDuration == 0 &&
|
||||||
|
sharedCfg.AssumeRoleDuration != nil &&
|
||||||
|
*sharedCfg.AssumeRoleDuration/time.Minute > 15 {
|
||||||
|
opt.Duration = *sharedCfg.AssumeRoleDuration
|
||||||
|
} else if sessOpts.AssumeRoleDuration != 0 {
|
||||||
|
opt.Duration = sessOpts.AssumeRoleDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume role with external ID
|
||||||
|
if len(sharedCfg.ExternalID) > 0 {
|
||||||
|
opt.ExternalID = aws.String(sharedCfg.ExternalID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume role with MFA
|
||||||
|
if len(sharedCfg.MFASerial) > 0 {
|
||||||
|
opt.SerialNumber = aws.String(sharedCfg.MFASerial)
|
||||||
|
opt.TokenProvider = sessOpts.AssumeRoleTokenProvider
|
||||||
|
}
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssumeRoleTokenProviderNotSetError is an error returned when creating a
|
||||||
|
// session when the MFAToken option is not set when shared config is configured
|
||||||
|
// load assume a role with an MFA token.
|
||||||
|
type AssumeRoleTokenProviderNotSetError struct{}
|
||||||
|
|
||||||
|
// Code is the short id of the error.
|
||||||
|
func (e AssumeRoleTokenProviderNotSetError) Code() string {
|
||||||
|
return "AssumeRoleTokenProviderNotSetError"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message is the description of the error
|
||||||
|
func (e AssumeRoleTokenProviderNotSetError) Message() string {
|
||||||
|
return fmt.Sprintf("assume role with MFA enabled, but AssumeRoleTokenProvider session option not set.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrigErr is the underlying error that caused the failure.
|
||||||
|
func (e AssumeRoleTokenProviderNotSetError) OrigErr() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error satisfies the error interface.
|
||||||
|
func (e AssumeRoleTokenProviderNotSetError) Error() string {
|
||||||
|
return awserr.SprintError(e.Code(), e.Message(), "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
type credProviderError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c credProviderError) Retrieve() (credentials.Value, error) {
|
||||||
|
return credentials.Value{}, c.Err
|
||||||
|
}
|
||||||
|
func (c credProviderError) IsExpired() bool {
|
||||||
|
return true
|
||||||
|
}
|
28
vendor/github.com/aws/aws-sdk-go/aws/session/custom_transport.go
generated
vendored
Normal file
28
vendor/github.com/aws/aws-sdk-go/aws/session/custom_transport.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//go:build go1.13
|
||||||
|
// +build go1.13
|
||||||
|
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Transport that should be used when a custom CA bundle is specified with the
|
||||||
|
// SDK.
|
||||||
|
func getCustomTransport() *http.Transport {
|
||||||
|
return &http.Transport{
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
DialContext: (&net.Dialer{
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
KeepAlive: 30 * time.Second,
|
||||||
|
DualStack: true,
|
||||||
|
}).DialContext,
|
||||||
|
ForceAttemptHTTP2: true,
|
||||||
|
MaxIdleConns: 100,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
27
vendor/github.com/aws/aws-sdk-go/aws/session/custom_transport_go1.12.go
generated
vendored
Normal file
27
vendor/github.com/aws/aws-sdk-go/aws/session/custom_transport_go1.12.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//go:build !go1.13 && go1.7
|
||||||
|
// +build !go1.13,go1.7
|
||||||
|
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Transport that should be used when a custom CA bundle is specified with the
|
||||||
|
// SDK.
|
||||||
|
func getCustomTransport() *http.Transport {
|
||||||
|
return &http.Transport{
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
DialContext: (&net.Dialer{
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
KeepAlive: 30 * time.Second,
|
||||||
|
DualStack: true,
|
||||||
|
}).DialContext,
|
||||||
|
MaxIdleConns: 100,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user