mirror of https://github.com/status-im/consul.git
vendor: add go-discover
This commit is contained in:
parent
02ed39cb2f
commit
e7285af6cc
|
@ -0,0 +1,354 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. “Contributor”
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. “Contributor Version”
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor’s Contribution.
|
||||||
|
|
||||||
|
1.3. “Contribution”
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. “Covered Software”
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. “Incompatible With Secondary Licenses”
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of version
|
||||||
|
1.1 or earlier of the License, but not also under the terms of a
|
||||||
|
Secondary License.
|
||||||
|
|
||||||
|
1.6. “Executable Form”
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. “Larger Work”
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a separate
|
||||||
|
file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. “License”
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. “Licensable”
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether at the
|
||||||
|
time of the initial grant or subsequently, any and all of the rights conveyed by
|
||||||
|
this License.
|
||||||
|
|
||||||
|
1.10. “Modifications”
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to, deletion
|
||||||
|
from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. “Patent Claims” of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method, process,
|
||||||
|
and apparatus claims, in any patent Licensable by such Contributor that
|
||||||
|
would be infringed, but for the grant of the License, by the making,
|
||||||
|
using, selling, offering for sale, having made, import, or transfer of
|
||||||
|
either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. “Secondary License”
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. “Source Code Form”
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. “You” (or “Your”)
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, “You” includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, “control” means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or as
|
||||||
|
part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its Contributions
|
||||||
|
or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution become
|
||||||
|
effective for each Contribution on the date the Contributor first distributes
|
||||||
|
such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under this
|
||||||
|
License. No additional rights or licenses will be implied from the distribution
|
||||||
|
or licensing of Covered Software under this License. Notwithstanding Section
|
||||||
|
2.1(b) above, no patent license is granted by a Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party’s
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of its
|
||||||
|
Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks, or
|
||||||
|
logos of any Contributor (except as may be necessary to comply with the
|
||||||
|
notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this License
|
||||||
|
(see Section 10.2) or under the terms of a Secondary License (if permitted
|
||||||
|
under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its Contributions
|
||||||
|
are its original creation(s) or it has sufficient rights to grant the
|
||||||
|
rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under applicable
|
||||||
|
copyright doctrines of fair use, fair dealing, or other equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under the
|
||||||
|
terms of this License. You must inform recipients that the Source Code Form
|
||||||
|
of the Covered Software is governed by the terms of this License, and how
|
||||||
|
they can obtain a copy of this License. You may not attempt to alter or
|
||||||
|
restrict the recipients’ rights in the Source Code Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this License,
|
||||||
|
or sublicense it under different terms, provided that the license for
|
||||||
|
the Executable Form does not attempt to limit or alter the recipients’
|
||||||
|
rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for the
|
||||||
|
Covered Software. If the Larger Work is a combination of Covered Software
|
||||||
|
with a work governed by one or more Secondary Licenses, and the Covered
|
||||||
|
Software is not Incompatible With Secondary Licenses, this License permits
|
||||||
|
You to additionally distribute such Covered Software under the terms of
|
||||||
|
such Secondary License(s), so that the recipient of the Larger Work may, at
|
||||||
|
their option, further distribute the Covered Software under the terms of
|
||||||
|
either this License or such Secondary License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices (including
|
||||||
|
copyright notices, patent notices, disclaimers of warranty, or limitations
|
||||||
|
of liability) contained within the Source Code Form of the Covered
|
||||||
|
Software, except that You may alter any license notices to the extent
|
||||||
|
required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on behalf
|
||||||
|
of any Contributor. You must make it absolutely clear that any such
|
||||||
|
warranty, support, indemnity, or liability obligation is offered by You
|
||||||
|
alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute, judicial
|
||||||
|
order, or regulation then You must: (a) comply with the terms of this License
|
||||||
|
to the maximum extent possible; and (b) describe the limitations and the code
|
||||||
|
they affect. Such description must be placed in a text file included with all
|
||||||
|
distributions of the Covered Software under this License. Except to the
|
||||||
|
extent prohibited by statute or regulation, such description must be
|
||||||
|
sufficiently detailed for a recipient of ordinary skill to be able to
|
||||||
|
understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
|
||||||
|
if such Contributor fails to notify You of the non-compliance by some
|
||||||
|
reasonable means prior to 60 days after You have come back into compliance.
|
||||||
|
Moreover, Your grants from a particular Contributor are reinstated on an
|
||||||
|
ongoing basis if such Contributor notifies You of the non-compliance by
|
||||||
|
some reasonable means, this is the first time You have received notice of
|
||||||
|
non-compliance with this License from such Contributor, and You become
|
||||||
|
compliant prior to 30 days after Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions, counter-claims,
|
||||||
|
and cross-claims) alleging that a Contributor Version directly or
|
||||||
|
indirectly infringes any patent, then the rights granted to You by any and
|
||||||
|
all Contributors for the Covered Software under Section 2.1 of this License
|
||||||
|
shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an “as is” basis, without
|
||||||
|
warranty of any kind, either expressed, implied, or statutory, including,
|
||||||
|
without limitation, warranties that the Covered Software is free of defects,
|
||||||
|
merchantable, fit for a particular purpose or non-infringing. The entire
|
||||||
|
risk as to the quality and performance of the Covered Software is with You.
|
||||||
|
Should any Covered Software prove defective in any respect, You (not any
|
||||||
|
Contributor) assume the cost of any necessary servicing, repair, or
|
||||||
|
correction. This disclaimer of warranty constitutes an essential part of this
|
||||||
|
License. No use of any Covered Software is authorized under this License
|
||||||
|
except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from such
|
||||||
|
party’s negligence to the extent applicable law prohibits such limitation.
|
||||||
|
Some jurisdictions do not allow the exclusion or limitation of incidental or
|
||||||
|
consequential damages, so this exclusion and limitation may not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts of
|
||||||
|
a jurisdiction where the defendant maintains its principal place of business
|
||||||
|
and such litigation shall be governed by laws of that jurisdiction, without
|
||||||
|
reference to its conflict-of-law provisions. Nothing in this Section shall
|
||||||
|
prevent a party’s ability to bring cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject matter
|
||||||
|
hereof. If any provision of this License is held to be unenforceable, such
|
||||||
|
provision shall be reformed only to the extent necessary to make it
|
||||||
|
enforceable. Any law or regulation which provides that the language of a
|
||||||
|
contract shall be construed against the drafter shall not be used to construe
|
||||||
|
this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version of
|
||||||
|
the License under which You originally received the Covered Software, or
|
||||||
|
under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a modified
|
||||||
|
version of this License if you rename the license and remove any
|
||||||
|
references to the name of the license steward (except to note that such
|
||||||
|
modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file, then
|
||||||
|
You may include the notice in a location (such as a LICENSE file in a relevant
|
||||||
|
directory) where a recipient would be likely to look for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - “Incompatible With Secondary Licenses” Notice
|
||||||
|
|
||||||
|
This Source Code Form is “Incompatible
|
||||||
|
With Secondary Licenses”, as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
# Go Discover Nodes for Cloud Providers [![Build Status](https://travis-ci.org/hashicorp/go-discover.svg?branch=master)](https://travis-ci.org/hashicorp/go-discover) [![GoDoc](https://godoc.org/github.com/hashicorp/go-discover?status.svg)](https://godoc.org/github.com/hashicorp/go-discover)
|
||||||
|
|
||||||
|
|
||||||
|
`go-discover` is a Go (golang) library and command line tool to discover
|
||||||
|
ip addresses of nodes in cloud environments based on meta information
|
||||||
|
like tags provided by the environment.
|
||||||
|
|
||||||
|
The configuration for the providers is provided as a list of `key=val
|
||||||
|
key=val ...` tuples where the values can be URL encoded. The provider is
|
||||||
|
determined through the `provider` key. Effectively, only spaces have to
|
||||||
|
be encoded with a `+` and on the command line you have to observe
|
||||||
|
quoting rules with your shell.
|
||||||
|
|
||||||
|
### Supported Providers
|
||||||
|
|
||||||
|
The following cloud providers have implementations in the go-discover/provider
|
||||||
|
sub packages. Additional providers can be added through the [Register](https://godoc.org/github.com/hashicorp/go-discover#Register)
|
||||||
|
function.
|
||||||
|
|
||||||
|
* Amazon AWS [Config options](http://godoc.org/github.com/hashicorp/go-discover/aws)
|
||||||
|
* Google Cloud [Config options](http://godoc.org/github.com/hashicorp/go-discover/gce)
|
||||||
|
* Microsoft Azure [Config options](http://godoc.org/github.com/hashicorp/go-discover/azure)
|
||||||
|
* SoftLayer [Config options](http://godoc.org/github.com/hashicorp/go-discover/softlayer)
|
||||||
|
|
||||||
|
### Config Example
|
||||||
|
|
||||||
|
```
|
||||||
|
# Amazon AWS
|
||||||
|
provider=aws region=eu-west-1 tag_key=consul tag_value=... access_key_id=... secret_access_key=...
|
||||||
|
|
||||||
|
# Google Cloud
|
||||||
|
provider=gce project_name=... zone_pattern=eu-west-* tag_value=consul credentials_file=...
|
||||||
|
|
||||||
|
# Microsoft Azure
|
||||||
|
provider=azure tag_name=consul tag_value=... tenant_id=... client_id=... subscription_id=... secret_access_key=...
|
||||||
|
|
||||||
|
# SoftLayer
|
||||||
|
provider=softlayer datacenter=dal06 tag_value=consul username=... api_key=...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Command Line Tool Usage
|
||||||
|
|
||||||
|
Install the command line tool with:
|
||||||
|
|
||||||
|
```
|
||||||
|
go get -u github.com/hashicorp/go-discover/cmd/discover
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run it with:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ discover addrs provider=aws region=eu-west-1 ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Library Usage
|
||||||
|
|
||||||
|
Install the library with:
|
||||||
|
|
||||||
|
```
|
||||||
|
go get -u github.com/hashicorp/go-discover
|
||||||
|
```
|
||||||
|
|
||||||
|
Supported providers need to be registered by importing them similar
|
||||||
|
to database drivers for the `database/sql` package.
|
||||||
|
|
||||||
|
Import the `go-discover` package and any provider package
|
||||||
|
you want to support.
|
||||||
|
|
||||||
|
```go
|
||||||
|
// support only AWS and GCE
|
||||||
|
import (
|
||||||
|
discover "github.com/hashicorp/go-discover"
|
||||||
|
|
||||||
|
_ "github.com/hashicorp/go-discover/provider/aws"
|
||||||
|
_ "github.com/hashicorp/go-discover/provider/gce"
|
||||||
|
)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
To import all known providers at once you can use the convenience
|
||||||
|
package `all`.
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
// support all providers supported by go-discover
|
||||||
|
import (
|
||||||
|
discover "github.com/hashicorp/go-discover"
|
||||||
|
|
||||||
|
_ "github.com/hashicorp/go-discover/provider/all"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Then call the `discover.Addrs` function with the arguments
|
||||||
|
for the provider you want to use:
|
||||||
|
|
||||||
|
```go
|
||||||
|
# use ioutil.Discard for no log output
|
||||||
|
l := log.New(os.Stderr, "", log.LstdFlags)
|
||||||
|
cfg := "provider=aws region=eu-west-1 ..."
|
||||||
|
addrs, err := discover.Addrs(cfg, l)
|
||||||
|
```
|
||||||
|
|
||||||
|
For complete API documentation, see
|
||||||
|
[GoDoc](https://godoc.org/github.com/hashicorp/go-discover). The configuration
|
||||||
|
for the supported providers is documented in the
|
||||||
|
[providers](https://godoc.org/github.com/hashicorp/go-discover/provider)
|
||||||
|
sub-package.
|
|
@ -0,0 +1,61 @@
|
||||||
|
package discover
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config stores key/value pairs for the discovery
|
||||||
|
// functions to use.
|
||||||
|
type Config map[string]string
|
||||||
|
|
||||||
|
// Parse parses a "key=val key=val ..." string into
|
||||||
|
// a config map. Values are URL escaped.
|
||||||
|
func Parse(s string) (Config, error) {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
if s == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
c := Config{}
|
||||||
|
for _, v := range strings.Fields(s) {
|
||||||
|
p := strings.SplitN(v, "=", 2)
|
||||||
|
if len(p) != 2 {
|
||||||
|
return nil, fmt.Errorf("invalid format: %s", v)
|
||||||
|
}
|
||||||
|
key := p[0]
|
||||||
|
val, err := url.QueryUnescape(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid format: %s", v)
|
||||||
|
}
|
||||||
|
c[key] = val
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String formats a config map into the "key=val key=val ..."
|
||||||
|
// understood by Parse. The order of the keys is stable.
|
||||||
|
func (c Config) String() string {
|
||||||
|
// sort 'provider' to the front and keep the keys stable.
|
||||||
|
var keys []string
|
||||||
|
for k := range c {
|
||||||
|
if k != "provider" {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
keys = append([]string{"provider"}, keys...)
|
||||||
|
|
||||||
|
var vals []string
|
||||||
|
for _, k := range keys {
|
||||||
|
v := c[k]
|
||||||
|
if v == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v = k + "=" + url.QueryEscape(v)
|
||||||
|
vals = append(vals, v)
|
||||||
|
}
|
||||||
|
return strings.Join(vals, " ")
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Package discover provides functions to get metadata for different
|
||||||
|
// cloud environments.
|
||||||
|
package discover
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Provider interface {
|
||||||
|
Addrs(args map[string]string, l *log.Logger) ([]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
mu sync.Mutex
|
||||||
|
providers = map[string]Provider{}
|
||||||
|
helps = map[string]string{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Register adds a new provider for the given name. If the
|
||||||
|
// provider is nil or already registered the function panics.
|
||||||
|
func Register(name string, provider Provider, help string) {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
if provider == nil {
|
||||||
|
panic("discover: Register called with nil provider")
|
||||||
|
}
|
||||||
|
if _, dup := providers[name]; dup {
|
||||||
|
panic("discover: Register called twice for provider " + name)
|
||||||
|
}
|
||||||
|
providers[name] = provider
|
||||||
|
helps[name] = help
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProviderNames returns the names of the registered providers.
|
||||||
|
func ProviderNames() []string {
|
||||||
|
var names []string
|
||||||
|
for n := range helps {
|
||||||
|
names = append(names, n)
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalHelp = `The options for discovering ip addresses are provided as a
|
||||||
|
single string value in "key=value key=value ..." format where
|
||||||
|
the values are URL encoded.
|
||||||
|
|
||||||
|
provider=aws region=eu-west-1 ...
|
||||||
|
|
||||||
|
The options are provider specific and are listed below.
|
||||||
|
`
|
||||||
|
|
||||||
|
// Help describes the format of the configuration string for address discovery
|
||||||
|
// and the various provider specific options.
|
||||||
|
func Help() string {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
h := []string{globalHelp}
|
||||||
|
for _, name := range ProviderNames() {
|
||||||
|
h = append(h, helps[name])
|
||||||
|
}
|
||||||
|
return strings.Join(h, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addrs discovers ip addresses of nodes that match the given filter criteria.
|
||||||
|
// The config string must have the format 'provider=xxx key=val key=val ...'
|
||||||
|
// where the keys and values are provider specific. The values are URL encoded.
|
||||||
|
func Addrs(cfg string, l *log.Logger) ([]string, error) {
|
||||||
|
args, err := Parse(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("discover: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := args["provider"]
|
||||||
|
if name == "" {
|
||||||
|
return nil, fmt.Errorf("discover: no provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
p := providers[name]
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
if p == nil {
|
||||||
|
return nil, fmt.Errorf("discover: unknown provider " + name)
|
||||||
|
}
|
||||||
|
return p.Addrs(args, l)
|
||||||
|
}
|
104
vendor/github.com/hashicorp/go-discover/provider/aws/aws_discover.go
generated
vendored
Normal file
104
vendor/github.com/hashicorp/go-discover/provider/aws/aws_discover.go
generated
vendored
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// Package aws provides node discovery for Amazon AWS.
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
|
discover "github.com/hashicorp/go-discover"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
discover.Register("aws", &Provider{}, Help)
|
||||||
|
}
|
||||||
|
|
||||||
|
var Help = `Amazon AWS:
|
||||||
|
|
||||||
|
provider: "aws"
|
||||||
|
region: The AWS region. Default to region of instance.
|
||||||
|
tag_key: The tag key to filter on
|
||||||
|
tag_value: The tag value to filter on
|
||||||
|
access_key_id: The AWS access key to use
|
||||||
|
secret_access_key: The AWS secret access key to use
|
||||||
|
|
||||||
|
The only required IAM permission is 'ec2:DescribeInstances'. It is
|
||||||
|
recommended you make a dedicated key used only for auto-joining.
|
||||||
|
`
|
||||||
|
|
||||||
|
type Provider struct{}
|
||||||
|
|
||||||
|
func (p *Provider) Addrs(args map[string]string, l *log.Logger) ([]string, error) {
|
||||||
|
if args["provider"] != "aws" {
|
||||||
|
return nil, fmt.Errorf("discover-aws: invalid provider " + args["provider"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if l == nil {
|
||||||
|
l = log.New(ioutil.Discard, "", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
region := args["region"]
|
||||||
|
tagKey := args["tag_key"]
|
||||||
|
tagValue := args["tag_value"]
|
||||||
|
accessKey := args["access_key_id"]
|
||||||
|
secretKey := args["secret_access_key"]
|
||||||
|
|
||||||
|
if region == "" {
|
||||||
|
l.Printf("[INFO] discover-aws: Looking up region")
|
||||||
|
ec2meta := ec2metadata.New(session.New())
|
||||||
|
identity, err := ec2meta.GetInstanceIdentityDocument()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("discover-aws: %s", err)
|
||||||
|
}
|
||||||
|
region = identity.Region
|
||||||
|
}
|
||||||
|
l.Printf("[INFO] discover-aws: Region is %s", region)
|
||||||
|
|
||||||
|
svc := ec2.New(session.New(), &aws.Config{
|
||||||
|
Region: ®ion,
|
||||||
|
Credentials: credentials.NewChainCredentials(
|
||||||
|
[]credentials.Provider{
|
||||||
|
&credentials.StaticProvider{
|
||||||
|
Value: credentials.Value{
|
||||||
|
AccessKeyID: accessKey,
|
||||||
|
SecretAccessKey: secretKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&credentials.EnvProvider{},
|
||||||
|
&credentials.SharedCredentialsProvider{},
|
||||||
|
defaults.RemoteCredProvider(*(defaults.Config()), defaults.Handlers()),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
resp, err := svc.DescribeInstances(&ec2.DescribeInstancesInput{
|
||||||
|
Filters: []*ec2.Filter{
|
||||||
|
{
|
||||||
|
Name: aws.String("tag:" + tagKey),
|
||||||
|
Values: []*string{aws.String(tagValue)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("discover-aws: %s", err)
|
||||||
|
}
|
||||||
|
l.Printf("[INFO] discover-aws: Filter instances by %s=%s", tagKey, tagValue)
|
||||||
|
|
||||||
|
var addrs []string
|
||||||
|
for i := range resp.Reservations {
|
||||||
|
for _, inst := range resp.Reservations[i].Instances {
|
||||||
|
// Terminated instances don't have the PrivateIpAddress field
|
||||||
|
if inst.PrivateIpAddress == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l.Printf("[INFO] discover-aws: Found %x", *inst.PrivateIpAddress)
|
||||||
|
addrs = append(addrs, *inst.PrivateIpAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addrs, nil
|
||||||
|
}
|
202
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/LICENSE.txt
generated
vendored
Normal file
202
vendor/github.com/hashicorp/go-discover/provider/aws/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/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/NOTICE.txt
generated
vendored
Normal file
3
vendor/github.com/hashicorp/go-discover/provider/aws/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.
|
145
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awserr/error.go
generated
vendored
Normal file
145
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awserr/error.go
generated
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
// 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 new request error wrapper for the given Error
|
||||||
|
// provided.
|
||||||
|
func NewRequestFailure(err Error, statusCode int, reqID string) RequestFailure {
|
||||||
|
return newRequestError(err, statusCode, reqID)
|
||||||
|
}
|
194
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awserr/types.go
generated
vendored
Normal file
194
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awserr/types.go
generated
vendored
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
package awserr
|
||||||
|
|
||||||
|
import "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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 += fmt.Sprintf("%s", 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/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go
generated
vendored
Normal file
108
vendor/github.com/hashicorp/go-discover/provider/aws/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/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go
generated
vendored
Normal file
27
vendor/github.com/hashicorp/go-discover/provider/aws/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 the 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())
|
||||||
|
}
|
222
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go
generated
vendored
Normal file
222
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go
generated
vendored
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
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.ToLower(name) == strings.ToLower(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{}) {
|
||||||
|
if rvals := rValuesAtPath(i, path, true, false, v == nil); rvals != 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
113
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go
generated
vendored
Normal file
113
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go
generated
vendored
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
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)
|
||||||
|
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||||
|
buf.WriteString(n + ": ")
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
89
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go
generated
vendored
Normal file
89
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go
generated
vendored
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
package awsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StringValue returns the string representation of a value.
|
||||||
|
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")
|
||||||
|
|
||||||
|
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.IsNil() {
|
||||||
|
continue // ignore unset fields
|
||||||
|
}
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, n := range names {
|
||||||
|
val := v.FieldByName(n)
|
||||||
|
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||||
|
buf.WriteString(n + ": ")
|
||||||
|
stringValue(val, indent+2, buf)
|
||||||
|
|
||||||
|
if i < len(names)-1 {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
146
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/client/client.go
generated
vendored
Normal file
146
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/client/client.go
generated
vendored
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http/httputil"
|
||||||
|
|
||||||
|
"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
|
||||||
|
Endpoint string
|
||||||
|
SigningRegion string
|
||||||
|
SigningName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 3
|
||||||
|
}
|
||||||
|
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() {
|
||||||
|
if !c.Config.LogLevel.AtLeast(aws.LogDebug) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Handlers.Send.PushFront(logRequest)
|
||||||
|
c.Handlers.Send.PushBack(logResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
const logReqMsg = `DEBUG: Request %s/%s Details:
|
||||||
|
---[ REQUEST POST-SIGN ]-----------------------------
|
||||||
|
%s
|
||||||
|
-----------------------------------------------------`
|
||||||
|
|
||||||
|
const logReqErrMsg = `DEBUG ERROR: Request %s/%s:
|
||||||
|
---[ REQUEST DUMP ERROR ]-----------------------------
|
||||||
|
%s
|
||||||
|
-----------------------------------------------------`
|
||||||
|
|
||||||
|
func logRequest(r *request.Request) {
|
||||||
|
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||||
|
dumpedBody, 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 {
|
||||||
|
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
|
||||||
|
// Body as a NoOpCloser and will not be reset after read by the HTTP
|
||||||
|
// client reader.
|
||||||
|
r.ResetBody()
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
|
||||||
|
}
|
||||||
|
|
||||||
|
const logRespMsg = `DEBUG: Response %s/%s Details:
|
||||||
|
---[ RESPONSE ]--------------------------------------
|
||||||
|
%s
|
||||||
|
-----------------------------------------------------`
|
||||||
|
|
||||||
|
const logRespErrMsg = `DEBUG ERROR: Response %s/%s:
|
||||||
|
---[ RESPONSE DUMP ERROR ]-----------------------------
|
||||||
|
%s
|
||||||
|
-----------------------------------------------------`
|
||||||
|
|
||||||
|
func logResponse(r *request.Request) {
|
||||||
|
var msg = "no response data"
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||||
|
dumpedBody, err := httputil.DumpResponse(r.HTTPResponse, logBody)
|
||||||
|
if err != nil {
|
||||||
|
r.Config.Logger.Log(fmt.Sprintf(logRespErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = string(dumpedBody)
|
||||||
|
} else if r.Error != nil {
|
||||||
|
msg = r.Error.Error()
|
||||||
|
}
|
||||||
|
r.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.ClientInfo.ServiceName, r.Operation.Name, msg))
|
||||||
|
}
|
90
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go
generated
vendored
Normal file
90
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go
generated
vendored
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultRetryer implements basic retry logic using exponential backoff for
|
||||||
|
// most services. If you want to implement custom retry logic, implement the
|
||||||
|
// request.Retryer interface or create a structure type that composes this
|
||||||
|
// struct and override the specific methods. For example, to override only
|
||||||
|
// the MaxRetries method:
|
||||||
|
//
|
||||||
|
// type retryer struct {
|
||||||
|
// service.DefaultRetryer
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // This implementation always has 100 max retries
|
||||||
|
// func (d retryer) MaxRetries() uint { return 100 }
|
||||||
|
type DefaultRetryer struct {
|
||||||
|
NumMaxRetries int
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
var seededRand = rand.New(&lockedSource{src: rand.NewSource(time.Now().UnixNano())})
|
||||||
|
|
||||||
|
// RetryRules returns the delay duration before retrying this request again
|
||||||
|
func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
|
||||||
|
// Set the upper limit of delay in retrying at ~five minutes
|
||||||
|
minTime := 30
|
||||||
|
throttle := d.shouldThrottle(r)
|
||||||
|
if throttle {
|
||||||
|
minTime = 500
|
||||||
|
}
|
||||||
|
|
||||||
|
retryCount := r.RetryCount
|
||||||
|
if retryCount > 13 {
|
||||||
|
retryCount = 13
|
||||||
|
} else if throttle && retryCount > 8 {
|
||||||
|
retryCount = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
delay := (1 << uint(retryCount)) * (seededRand.Intn(minTime) + minTime)
|
||||||
|
return time.Duration(delay) * time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldRetry returns true if the request should be retried.
|
||||||
|
func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
|
||||||
|
if r.HTTPResponse.StatusCode >= 500 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return r.IsErrorRetryable() || d.shouldThrottle(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldThrottle returns true if the request should be throttled.
|
||||||
|
func (d DefaultRetryer) shouldThrottle(r *request.Request) bool {
|
||||||
|
if r.HTTPResponse.StatusCode == 502 ||
|
||||||
|
r.HTTPResponse.StatusCode == 503 ||
|
||||||
|
r.HTTPResponse.StatusCode == 504 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return r.IsErrorThrottle()
|
||||||
|
}
|
||||||
|
|
||||||
|
// lockedSource is a thread-safe implementation of rand.Source
|
||||||
|
type lockedSource struct {
|
||||||
|
lk sync.Mutex
|
||||||
|
src rand.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *lockedSource) Int63() (n int64) {
|
||||||
|
r.lk.Lock()
|
||||||
|
n = r.src.Int63()
|
||||||
|
r.lk.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *lockedSource) Seed(seed int64) {
|
||||||
|
r.lk.Lock()
|
||||||
|
r.src.Seed(seed)
|
||||||
|
r.lk.Unlock()
|
||||||
|
}
|
12
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
Normal file
12
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package metadata
|
||||||
|
|
||||||
|
// ClientInfo wraps immutable data from the client.Client structure.
|
||||||
|
type ClientInfo struct {
|
||||||
|
ServiceName string
|
||||||
|
APIVersion string
|
||||||
|
Endpoint string
|
||||||
|
SigningName string
|
||||||
|
SigningRegion string
|
||||||
|
JSONVersion string
|
||||||
|
TargetPrefix string
|
||||||
|
}
|
452
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
Normal file
452
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
Normal file
|
@ -0,0 +1,452 @@
|
||||||
|
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 tructure.
|
||||||
|
//
|
||||||
|
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||||
|
// // service clients.
|
||||||
|
// sess, err := 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 `""` 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
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// 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 request.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
|
||||||
|
// 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 disble 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
|
||||||
|
|
||||||
|
// 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, err := session.NewSession(aws.NewConfig().WithEC2MetadataDiableTimeoutOverride(true))
|
||||||
|
//
|
||||||
|
// svc := s3.New(sess)
|
||||||
|
//
|
||||||
|
EC2MetadataDisableTimeoutOverride *bool
|
||||||
|
|
||||||
|
// Instructs the endpiont 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 requets. 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, err := session.NewSession()
|
||||||
|
//
|
||||||
|
// svc := s3.New(sess, &aws.Config{
|
||||||
|
// UseDualStack: aws.Bool(true),
|
||||||
|
// })
|
||||||
|
UseDualStack *bool
|
||||||
|
|
||||||
|
// 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 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, err := 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 MaxRetry configuration to be shared by multiple
|
||||||
|
// // service clients.
|
||||||
|
// sess, err := 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.UseDualStack != nil {
|
||||||
|
dst.UseDualStack = other.UseDualStack
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.EC2MetadataDisableTimeoutOverride != nil {
|
||||||
|
dst.EC2MetadataDisableTimeoutOverride = other.EC2MetadataDisableTimeoutOverride
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.SleepDelay != nil {
|
||||||
|
dst.SleepDelay = other.SleepDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.DisableRestProtocolURICleaning != nil {
|
||||||
|
dst.DisableRestProtocolURICleaning = other.DisableRestProtocolURICleaning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
369
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/convert_types.go
generated
vendored
Normal file
369
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/convert_types.go
generated
vendored
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
182
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
generated
vendored
Normal file
182
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
generated
vendored
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
package corehandlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"runtime"
|
||||||
|
"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 aded 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 {
|
||||||
|
switch body := r.Body.(type) {
|
||||||
|
case nil:
|
||||||
|
length = 0
|
||||||
|
case lener:
|
||||||
|
length = int64(body.Len())
|
||||||
|
case io.Seeker:
|
||||||
|
r.BodyStart, _ = body.Seek(0, 1)
|
||||||
|
end, _ := body.Seek(0, 2)
|
||||||
|
body.Seek(r.BodyStart, 0) // make sure to seek back to original location
|
||||||
|
length = end - r.BodyStart
|
||||||
|
default:
|
||||||
|
panic("Cannot get length of body, must provide `ContentLength`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if 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")
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
// SDKVersionUserAgentHandler is a request handler for adding the SDK Version to the user agent.
|
||||||
|
var SDKVersionUserAgentHandler = request.NamedHandler{
|
||||||
|
Name: "core.SDKVersionUserAgentHandler",
|
||||||
|
Fn: request.MakeAddToUserAgentHandler(aws.SDKName, aws.SDKVersion,
|
||||||
|
runtime.Version(), runtime.GOOS, runtime.GOARCH),
|
||||||
|
}
|
||||||
|
|
||||||
|
var reStatusCode = regexp.MustCompile(`^(\d{3})`)
|
||||||
|
|
||||||
|
// ValidateReqSigHandler is a request handler to ensure that the request's
|
||||||
|
// signature doesn't expire before it is sent. This can happen when a request
|
||||||
|
// is built and signed signficantly before it is sent. Or significant delays
|
||||||
|
// occur whne 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10 minutes to allow for some clock skew/delays in transmission.
|
||||||
|
// Would be improved with aws/aws-sdk-go#423
|
||||||
|
if signedTime.Add(10 * time.Minute).After(time.Now()) {
|
||||||
|
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) {
|
||||||
|
var err error
|
||||||
|
r.HTTPResponse, err = r.Config.HTTPClient.Do(r.HTTPRequest)
|
||||||
|
if err != nil {
|
||||||
|
// 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 other request errors.
|
||||||
|
r.Error = awserr.New("RequestError", "send request failed", err)
|
||||||
|
r.Retryable = aws.Bool(true) // network errors are retryable
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
// 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", nil)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
r.Retryable = aws.Bool(r.ShouldRetry(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.WillRetry() {
|
||||||
|
r.RetryDelay = r.RetryRules(r)
|
||||||
|
r.Config.SleepDelay(r.RetryDelay)
|
||||||
|
|
||||||
|
// 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 == "" {
|
||||||
|
r.Error = aws.ErrMissingEndpoint
|
||||||
|
}
|
||||||
|
}}
|
17
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go
generated
vendored
Normal file
17
vendor/github.com/hashicorp/go-discover/provider/aws/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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
100
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go
generated
vendored
Normal file
100
vendor/github.com/hashicorp/go-discover/provider/aws/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
|
||||||
|
//
|
||||||
|
// @readonly
|
||||||
|
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 := NewChainCredentials(
|
||||||
|
// []Provider{
|
||||||
|
// &EnvProvider{},
|
||||||
|
// &EC2RoleProvider{
|
||||||
|
// Client: ec2metadata.New(sess),
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// // Usage of ChainCredentials with aws.Config
|
||||||
|
// svc := ec2.New(&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
|
||||||
|
}
|
223
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials.go
generated
vendored
Normal file
223
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials.go
generated
vendored
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
// 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 := 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 := NewCredentials(&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 := NewCredentials(&MyProvider{})
|
||||||
|
// credValue, err := creds.Get()
|
||||||
|
//
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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(&aws.Config{Credentials: AnonymousCredentials})
|
||||||
|
// // Access public S3 buckets.
|
||||||
|
//
|
||||||
|
// @readonly
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// Refresh 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
e.expiration = expiration
|
||||||
|
if window > 0 {
|
||||||
|
e.expiration = e.expiration.Add(-window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns if the credentials are expired.
|
||||||
|
func (e *Expiry) IsExpired() bool {
|
||||||
|
if e.CurrentTime == nil {
|
||||||
|
e.CurrentTime = time.Now
|
||||||
|
}
|
||||||
|
return e.expiration.Before(e.CurrentTime())
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Credentials provides synchronous 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 {
|
||||||
|
creds Value
|
||||||
|
forceRefresh bool
|
||||||
|
m sync.Mutex
|
||||||
|
|
||||||
|
provider Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentials returns a pointer to a new Credentials with the provider set.
|
||||||
|
func NewCredentials(provider Provider) *Credentials {
|
||||||
|
return &Credentials{
|
||||||
|
provider: provider,
|
||||||
|
forceRefresh: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
c.m.Lock()
|
||||||
|
defer c.m.Unlock()
|
||||||
|
|
||||||
|
if c.isExpired() {
|
||||||
|
creds, err := c.provider.Retrieve()
|
||||||
|
if err != nil {
|
||||||
|
return Value{}, err
|
||||||
|
}
|
||||||
|
c.creds = creds
|
||||||
|
c.forceRefresh = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.creds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.forceRefresh = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.Lock()
|
||||||
|
defer c.m.Unlock()
|
||||||
|
|
||||||
|
return c.isExpired()
|
||||||
|
}
|
||||||
|
|
||||||
|
// isExpired helper method wrapping the definition of expired credentials.
|
||||||
|
func (c *Credentials) isExpired() bool {
|
||||||
|
return c.forceRefresh || c.provider.IsExpired()
|
||||||
|
}
|
178
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
generated
vendored
Normal file
178
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
generated
vendored
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
package ec2rolecreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
credsList, err := requestCredList(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(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(client *ec2metadata.EC2Metadata) ([]string, error) {
|
||||||
|
resp, err := client.GetMetadata(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("SerializationError", "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(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) {
|
||||||
|
resp, err := client.GetMetadata(path.Join(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("SerializationError",
|
||||||
|
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
|
||||||
|
}
|
191
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go
generated
vendored
Normal file
191
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 Credentials wrapper for retrieving credentials
|
||||||
|
// from an arbitrary endpoint concurrently. The client will request the
|
||||||
|
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) {
|
||||||
|
resp, err := p.getCredentials()
|
||||||
|
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() (*getCredentialsOutput, error) {
|
||||||
|
op := &request.Operation{
|
||||||
|
Name: "GetCredentials",
|
||||||
|
HTTPMethod: "GET",
|
||||||
|
}
|
||||||
|
|
||||||
|
out := &getCredentialsOutput{}
|
||||||
|
req := p.Client.NewRequest(op, nil, out)
|
||||||
|
req.HTTPRequest.Header.Set("Accept", "application/json")
|
||||||
|
|
||||||
|
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("SerializationError",
|
||||||
|
"failed to decode endpoint credentials",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalError(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
|
||||||
|
var errOut errorOutput
|
||||||
|
if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&errOut); err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError",
|
||||||
|
"failed to decode endpoint credentials",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
77
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go
generated
vendored
Normal file
77
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go
generated
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
// @readonly
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
// @readonly
|
||||||
|
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/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini
generated
vendored
Normal file
12
vendor/github.com/hashicorp/go-discover/provider/aws/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
|
151
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go
generated
vendored
Normal file
151
vendor/github.com/hashicorp/go-discover/provider/aws/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"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/go-ini/ini"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SharedCredsProviderName provides a name of SharedCreds provider
|
||||||
|
const SharedCredsProviderName = "SharedCredentialsProvider"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found.
|
||||||
|
//
|
||||||
|
// @readonly
|
||||||
|
ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
// A SharedCredentialsProvider retrieves 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.Load(filename)
|
||||||
|
if err != nil {
|
||||||
|
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to load shared credentials file", err)
|
||||||
|
}
|
||||||
|
iniProfile, err := config.GetSection(profile)
|
||||||
|
if err != nil {
|
||||||
|
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to get profile", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := iniProfile.GetKey("aws_access_key_id")
|
||||||
|
if err != nil {
|
||||||
|
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsAccessKey",
|
||||||
|
fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename),
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
secret, err := iniProfile.GetKey("aws_secret_access_key")
|
||||||
|
if err != nil {
|
||||||
|
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.Key("aws_session_token")
|
||||||
|
|
||||||
|
return Value{
|
||||||
|
AccessKeyID: id.String(),
|
||||||
|
SecretAccessKey: secret.String(),
|
||||||
|
SessionToken: token.String(),
|
||||||
|
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 p.Filename == "" {
|
||||||
|
if p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); p.Filename != "" {
|
||||||
|
return p.Filename, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
homeDir := os.Getenv("HOME") // *nix
|
||||||
|
if homeDir == "" { // Windows
|
||||||
|
homeDir = os.Getenv("USERPROFILE")
|
||||||
|
}
|
||||||
|
if homeDir == "" {
|
||||||
|
return "", ErrSharedCredentialsHomeNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Filename = filepath.Join(homeDir, ".aws", "credentials")
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
57
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider.go
generated
vendored
Normal file
57
vendor/github.com/hashicorp/go-discover/provider/aws/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.
|
||||||
|
//
|
||||||
|
// @readonly
|
||||||
|
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.
|
||||||
|
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
|
||||||
|
}
|
161
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
Normal file
161
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
// 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.
|
||||||
|
package stscreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/client"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/service/sts"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 provider must be used explicitly,
|
||||||
|
// as it is not included in the credentials chain.
|
||||||
|
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
|
||||||
|
|
||||||
|
// 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 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.
|
||||||
|
TokenCode *string
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||||
|
// role will be named after a nanosecond timestamp of this operation.
|
||||||
|
//
|
||||||
|
// Takes a Config provider to create the STS client. The ConfigProvider is
|
||||||
|
// satisfied by the session.Session type.
|
||||||
|
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 object wrapping the
|
||||||
|
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||||
|
// role will be named after a nanosecond timestamp of this operation.
|
||||||
|
//
|
||||||
|
// Takes an AssumeRoler which can be satisfiede by the STS client.
|
||||||
|
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) {
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
input := &sts.AssumeRoleInput{
|
||||||
|
DurationSeconds: aws.Int64(int64(p.Duration / time.Second)),
|
||||||
|
RoleArn: aws.String(p.RoleARN),
|
||||||
|
RoleSessionName: aws.String(p.RoleSessionName),
|
||||||
|
ExternalId: p.ExternalID,
|
||||||
|
}
|
||||||
|
if p.Policy != nil {
|
||||||
|
input.Policy = p.Policy
|
||||||
|
}
|
||||||
|
if p.SerialNumber != nil && p.TokenCode != nil {
|
||||||
|
input.SerialNumber = p.SerialNumber
|
||||||
|
input.TokenCode = p.TokenCode
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
134
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go
generated
vendored
Normal file
134
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go
generated
vendored
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
// 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/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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).
|
||||||
|
WithSleepDelay(time.Sleep).
|
||||||
|
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.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: []credentials.Provider{
|
||||||
|
&credentials.EnvProvider{},
|
||||||
|
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||||
|
RemoteCredProvider(*cfg, handlers),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteCredProvider returns a credenitials provider for the default remote
|
||||||
|
// endpoints such as EC2 or ECS Roles.
|
||||||
|
func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||||
|
ecsCredURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")
|
||||||
|
|
||||||
|
if len(ecsCredURI) > 0 {
|
||||||
|
return ecsCredProvider(cfg, handlers, ecsCredURI)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ec2RoleProvider(cfg, handlers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ecsCredProvider(cfg aws.Config, handlers request.Handlers, uri string) credentials.Provider {
|
||||||
|
const host = `169.254.170.2`
|
||||||
|
|
||||||
|
return endpointcreds.NewProviderClient(cfg, handlers,
|
||||||
|
fmt.Sprintf("http://%s%s", host, uri),
|
||||||
|
func(p *endpointcreds.Provider) {
|
||||||
|
p.ExpiryWindow = 5 * time.Minute
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
162
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go
generated
vendored
Normal file
162
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go
generated
vendored
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
package ec2metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetMetadata uses the path provided to request information from the EC2
|
||||||
|
// instance metdata service. The content will be returned as a string, or
|
||||||
|
// error if the request failed.
|
||||||
|
func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
||||||
|
op := &request.Operation{
|
||||||
|
Name: "GetMetadata",
|
||||||
|
HTTPMethod: "GET",
|
||||||
|
HTTPPath: path.Join("/", "meta-data", p),
|
||||||
|
}
|
||||||
|
|
||||||
|
output := &metadataOutput{}
|
||||||
|
req := c.NewRequest(op, nil, output)
|
||||||
|
|
||||||
|
return output.Content, req.Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
op := &request.Operation{
|
||||||
|
Name: "GetUserData",
|
||||||
|
HTTPMethod: "GET",
|
||||||
|
HTTPPath: path.Join("/", "user-data"),
|
||||||
|
}
|
||||||
|
|
||||||
|
output := &metadataOutput{}
|
||||||
|
req := c.NewRequest(op, nil, output)
|
||||||
|
req.Handlers.UnmarshalError.PushBack(func(r *request.Request) {
|
||||||
|
if r.HTTPResponse.StatusCode == http.StatusNotFound {
|
||||||
|
r.Error = awserr.New("NotFoundError", "user-data not found", r.Error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return output.Content, req.Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
op := &request.Operation{
|
||||||
|
Name: "GetDynamicData",
|
||||||
|
HTTPMethod: "GET",
|
||||||
|
HTTPPath: path.Join("/", "dynamic", p),
|
||||||
|
}
|
||||||
|
|
||||||
|
output := &metadataOutput{}
|
||||||
|
req := c.NewRequest(op, nil, output)
|
||||||
|
|
||||||
|
return output.Content, req.Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
resp, err := c.GetDynamicData("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("SerializationError",
|
||||||
|
"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) {
|
||||||
|
resp, err := c.GetMetadata("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("SerializationError",
|
||||||
|
"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) {
|
||||||
|
resp, err := c.GetMetadata("placement/availability-zone")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns region without the suffix. Eg: us-west-2a becomes us-west-2
|
||||||
|
return resp[:len(resp)-1], 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 {
|
||||||
|
if _, err := c.GetMetadata("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"`
|
||||||
|
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"`
|
||||||
|
}
|
124
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go
generated
vendored
Normal file
124
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go
generated
vendored
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// Package ec2metadata provides the client for making API calls to the
|
||||||
|
// EC2 Metadata service.
|
||||||
|
package ec2metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"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/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServiceName is the name of the service.
|
||||||
|
const ServiceName = "ec2metadata"
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 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: 5 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := &EC2Metadata{
|
||||||
|
Client: client.New(
|
||||||
|
cfg,
|
||||||
|
metadata.ClientInfo{
|
||||||
|
ServiceName: ServiceName,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
APIVersion: "latest",
|
||||||
|
},
|
||||||
|
handlers,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.Handlers.Unmarshal.PushBack(unmarshalHandler)
|
||||||
|
svc.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||||
|
svc.Handlers.Validate.Clear()
|
||||||
|
svc.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalHandler(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata respose", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if data, ok := r.Data.(*metadataOutput); ok {
|
||||||
|
data.Content = b.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalError(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata error respose", err)
|
||||||
|
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("EC2MetadataError", "failed to make EC2Metadata request", errors.New(b.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateEndpointHandler(r *request.Request) {
|
||||||
|
if r.ClientInfo.Endpoint == "" {
|
||||||
|
r.Error = aws.ErrMissingEndpoint
|
||||||
|
}
|
||||||
|
}
|
133
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode.go
generated
vendored
Normal file
133
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode.go
generated
vendored
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
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]
|
||||||
|
custAddEC2Metadata(p)
|
||||||
|
custAddS3DualStack(p)
|
||||||
|
custRmIotDataService(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func custAddS3DualStack(p *partition) {
|
||||||
|
if p.ID != "aws" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s, ok := p.Services["s3"]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Defaults.HasDualStack = boxedTrue
|
||||||
|
s.Defaults.DualStackHostname = "{service}.dualstack.{region}.{dnsSuffix}"
|
||||||
|
|
||||||
|
p.Services["s3"] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func custAddEC2Metadata(p *partition) {
|
||||||
|
p.Services["ec2metadata"] = service{
|
||||||
|
IsRegionalized: boxedFalse,
|
||||||
|
PartitionEndpoint: "aws-global",
|
||||||
|
Endpoints: endpoints{
|
||||||
|
"aws-global": endpoint{
|
||||||
|
Hostname: "169.254.169.254/latest",
|
||||||
|
Protocols: []string{"http"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func custRmIotDataService(p *partition) {
|
||||||
|
delete(p.Services, "data.iot")
|
||||||
|
}
|
||||||
|
|
||||||
|
type decodeModelError struct {
|
||||||
|
awsError
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDecodeModelError(msg string, err error) decodeModelError {
|
||||||
|
return decodeModelError{
|
||||||
|
awsError: awserr.New("DecodeEndpointsModelError", msg, err),
|
||||||
|
}
|
||||||
|
}
|
2042
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
generated
vendored
Normal file
2042
vendor/github.com/hashicorp/go-discover/provider/aws/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
66
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/doc.go
generated
vendored
Normal file
66
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// 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.Name)
|
||||||
|
// for id, _ := range p.Regions() {
|
||||||
|
// fmt.Println("*", id)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fmt.Println("Services for", p.Name)
|
||||||
|
// 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
|
397
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints.go
generated
vendored
Normal file
397
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints.go
generated
vendored
Normal file
|
@ -0,0 +1,397 @@
|
||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
UseDualStack bool
|
||||||
|
|
||||||
|
// 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 unkonwn 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func UseDualStackOption(o *Options) {
|
||||||
|
o.UseDualStack = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Partition provides the ability to enumerate the partition's regions
|
||||||
|
// and services.
|
||||||
|
type Partition struct {
|
||||||
|
id string
|
||||||
|
p *partition
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 my 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 := map[string]Region{}
|
||||||
|
for id := range p.p.Regions {
|
||||||
|
rs[id] = Region{
|
||||||
|
id: id,
|
||||||
|
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 := map[string]Service{}
|
||||||
|
for id := range p.p.Services {
|
||||||
|
ss[id] = Service{
|
||||||
|
id: id,
|
||||||
|
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 }
|
||||||
|
|
||||||
|
// 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[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...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endpoints returns a map of Endpoints indexed by their ID for all known
|
||||||
|
// endpoints for a service.
|
||||||
|
func (s *Service) Endpoints() map[string]Endpoint {
|
||||||
|
es := map[string]Endpoint{}
|
||||||
|
for id := range s.p.Services[s.id].Endpoints {
|
||||||
|
es[id] = Endpoint{
|
||||||
|
id: id,
|
||||||
|
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 region that should be used for signing requests.
|
||||||
|
SigningRegion string
|
||||||
|
|
||||||
|
// The service name that should be used for signing requests.
|
||||||
|
SigningName string
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
//// NewEndpointNotFoundError builds and returns NewEndpointNotFoundError.
|
||||||
|
//func NewEndpointNotFoundError(p, s, r string) EndpointNotFoundError {
|
||||||
|
// return EndpointNotFoundError{
|
||||||
|
// awsError: awserr.New("EndpointNotFoundError", "unable to find endpoint", nil),
|
||||||
|
// Partition: p,
|
||||||
|
// Service: s,
|
||||||
|
// Region: r,
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// Error returns string representation of the error.
|
||||||
|
//func (e EndpointNotFoundError) Error() string {
|
||||||
|
// extra := fmt.Sprintf("partition: %q, service: %q, region: %q",
|
||||||
|
// e.Partition, e.Service, e.Region)
|
||||||
|
// return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// String returns the string representation of the error.
|
||||||
|
//func (e EndpointNotFoundError) String() string {
|
||||||
|
// return e.Error()
|
||||||
|
//}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
}
|
303
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model.go
generated
vendored
Normal file
303
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model.go
generated
vendored
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type partitions []partition
|
||||||
|
|
||||||
|
func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||||
|
var opt Options
|
||||||
|
opt.Set(opts...)
|
||||||
|
|
||||||
|
for i := 0; i < len(ps); i++ {
|
||||||
|
if !ps[i].canResolveEndpoint(service, region, opt.StrictMatching) {
|
||||||
|
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 partition struct {
|
||||||
|
ID string `json:"partition"`
|
||||||
|
Name string `json:"partitionName"`
|
||||||
|
DNSSuffix string `json:"dnsSuffix"`
|
||||||
|
RegionRegex regionRegex `json:"regionRegex"`
|
||||||
|
Defaults endpoint `json:"defaults"`
|
||||||
|
Regions regions `json:"regions"`
|
||||||
|
Services services `json:"services"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p partition) Partition() Partition {
|
||||||
|
return Partition{
|
||||||
|
id: p.ID,
|
||||||
|
p: &p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p partition) canResolveEndpoint(service, region string, strictMatch bool) bool {
|
||||||
|
s, hasService := p.Services[service]
|
||||||
|
_, hasEndpoint := s.Endpoints[region]
|
||||||
|
|
||||||
|
if hasEndpoint && hasService {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if strictMatch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.RegionRegex.MatchString(region)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) {
|
||||||
|
var opt Options
|
||||||
|
opt.Set(opts...)
|
||||||
|
|
||||||
|
s, hasService := p.Services[service]
|
||||||
|
if !(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))
|
||||||
|
}
|
||||||
|
|
||||||
|
e, hasEndpoint := s.endpointForRegion(region)
|
||||||
|
if !hasEndpoint && opt.StrictMatching {
|
||||||
|
return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(s.Endpoints))
|
||||||
|
}
|
||||||
|
|
||||||
|
defs := []endpoint{p.Defaults, s.Defaults}
|
||||||
|
return e.resolve(service, region, p.DNSSuffix, defs, opt), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func serviceList(ss services) []string {
|
||||||
|
list := make([]string, 0, len(ss))
|
||||||
|
for k := range ss {
|
||||||
|
list = append(list, k)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
func endpointList(es endpoints) []string {
|
||||||
|
list := make([]string, 0, len(es))
|
||||||
|
for k := range es {
|
||||||
|
list = append(list, k)
|
||||||
|
}
|
||||||
|
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 endpoint `json:"defaults"`
|
||||||
|
Endpoints endpoints `json:"endpoints"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) endpointForRegion(region string) (endpoint, bool) {
|
||||||
|
if s.IsRegionalized == boxedFalse {
|
||||||
|
return s.Endpoints[s.PartitionEndpoint], region == s.PartitionEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if e, ok := s.Endpoints[region]; ok {
|
||||||
|
return e, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unable to find any matching endpoint, return
|
||||||
|
// blank that will be used for generic endpoint creation.
|
||||||
|
return endpoint{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
type endpoints map[string]endpoint
|
||||||
|
|
||||||
|
type endpoint struct {
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
Protocols []string `json:"protocols"`
|
||||||
|
CredentialScope credentialScope `json:"credentialScope"`
|
||||||
|
|
||||||
|
// Custom fields not modeled
|
||||||
|
HasDualStack boxedBool `json:"-"`
|
||||||
|
DualStackHostname string `json:"-"`
|
||||||
|
|
||||||
|
// Signature Version not used
|
||||||
|
SignatureVersions []string `json:"signatureVersions"`
|
||||||
|
|
||||||
|
// SSLCommonName not used.
|
||||||
|
SSLCommonName string `json:"sslCommonName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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, region, dnsSuffix string, defs []endpoint, opts Options) ResolvedEndpoint {
|
||||||
|
var merged endpoint
|
||||||
|
for _, def := range defs {
|
||||||
|
merged.mergeIn(def)
|
||||||
|
}
|
||||||
|
merged.mergeIn(e)
|
||||||
|
e = merged
|
||||||
|
|
||||||
|
hostname := e.Hostname
|
||||||
|
|
||||||
|
// Offset the hostname for dualstack if enabled
|
||||||
|
if opts.UseDualStack && e.HasDualStack == boxedTrue {
|
||||||
|
hostname = e.DualStackHostname
|
||||||
|
}
|
||||||
|
|
||||||
|
u := strings.Replace(hostname, "{service}", service, 1)
|
||||||
|
u = strings.Replace(u, "{region}", region, 1)
|
||||||
|
u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
|
||||||
|
|
||||||
|
scheme := getEndpointScheme(e.Protocols, opts.DisableSSL)
|
||||||
|
u = fmt.Sprintf("%s://%s", scheme, u)
|
||||||
|
|
||||||
|
signingRegion := e.CredentialScope.Region
|
||||||
|
if len(signingRegion) == 0 {
|
||||||
|
signingRegion = region
|
||||||
|
}
|
||||||
|
signingName := e.CredentialScope.Service
|
||||||
|
if len(signingName) == 0 {
|
||||||
|
signingName = service
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResolvedEndpoint{
|
||||||
|
URL: u,
|
||||||
|
SigningRegion: signingRegion,
|
||||||
|
SigningName: signingName,
|
||||||
|
SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 other.HasDualStack != boxedBoolUnset {
|
||||||
|
e.HasDualStack = other.HasDualStack
|
||||||
|
}
|
||||||
|
if len(other.DualStackHostname) > 0 {
|
||||||
|
e.DualStackHostname = other.DualStackHostname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
334
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go
generated
vendored
Normal file
334
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go
generated
vendored
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
// +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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := template.Must(template.New("tmpl").Funcs(funcMap).Parse(v3Tmpl))
|
||||||
|
if err := tmpl.ExecuteTemplate(outFile, "defaults", resolver); 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
const v3Tmpl = `
|
||||||
|
{{ define "defaults" -}}
|
||||||
|
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||||
|
|
||||||
|
package endpoints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
{{ template "partition consts" . }}
|
||||||
|
|
||||||
|
{{ range $_, $partition := . }}
|
||||||
|
{{ template "partition region consts" $partition }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ template "service consts" . }}
|
||||||
|
|
||||||
|
{{ template "endpoint resolvers" . }}
|
||||||
|
{{- 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 . }}.
|
||||||
|
//
|
||||||
|
// 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 := endpoints.DefaultResolver()
|
||||||
|
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
|
||||||
|
// for _, p := range partitions {
|
||||||
|
// // ... inspect partitions
|
||||||
|
// }
|
||||||
|
func DefaultResolver() Resolver {
|
||||||
|
return defaultPartitions
|
||||||
|
}
|
||||||
|
|
||||||
|
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 EndpointIsSet .Defaults -}}
|
||||||
|
Defaults: {{ template "gocode Endpoint" .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 EndpointIsSet .Defaults -}}
|
||||||
|
Defaults: {{ template "gocode Endpoint" .Defaults -}},
|
||||||
|
{{- end }}
|
||||||
|
{{ if .Endpoints -}}
|
||||||
|
Endpoints: {{ template "gocode Endpoints" .Endpoints }},
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "gocode Endpoints" -}}
|
||||||
|
endpoints{
|
||||||
|
{{ range $id, $endpoint := . -}}
|
||||||
|
"{{ $id }}": {{ template "gocode Endpoint" $endpoint }},
|
||||||
|
{{ end }}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ define "gocode Endpoint" -}}
|
||||||
|
endpoint{
|
||||||
|
{{ StringIfSet "Hostname: %q,\n" .Hostname -}}
|
||||||
|
{{ 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 "HasDualStack: %s,\n" .HasDualStack -}}
|
||||||
|
{{ StringIfSet "DualStackHostname: %q,\n" .DualStackHostname -}}
|
||||||
|
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
`
|
17
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/errors.go
generated
vendored
Normal file
17
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
// @readonly
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
// @readonly
|
||||||
|
ErrMissingEndpoint = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
|
||||||
|
)
|
112
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/logger.go
generated
vendored
Normal file
112
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/logger.go
generated
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
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 nill, 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 nill, 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
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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...)
|
||||||
|
}
|
187
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go
generated
vendored
Normal file
187
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go
generated
vendored
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
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
|
||||||
|
Sign HandlerList
|
||||||
|
Send HandlerList
|
||||||
|
ValidateResponse HandlerList
|
||||||
|
Unmarshal HandlerList
|
||||||
|
UnmarshalMeta HandlerList
|
||||||
|
UnmarshalError HandlerList
|
||||||
|
Retry HandlerList
|
||||||
|
AfterRetry HandlerList
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy returns of this handler's lists.
|
||||||
|
func (h *Handlers) Copy() Handlers {
|
||||||
|
return Handlers{
|
||||||
|
Validate: h.Validate.copy(),
|
||||||
|
Build: h.Build.copy(),
|
||||||
|
Sign: h.Sign.copy(),
|
||||||
|
Send: h.Send.copy(),
|
||||||
|
ValidateResponse: h.ValidateResponse.copy(),
|
||||||
|
Unmarshal: h.Unmarshal.copy(),
|
||||||
|
UnmarshalError: h.UnmarshalError.copy(),
|
||||||
|
UnmarshalMeta: h.UnmarshalMeta.copy(),
|
||||||
|
Retry: h.Retry.copy(),
|
||||||
|
AfterRetry: h.AfterRetry.copy(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear removes callback functions for all handlers
|
||||||
|
func (h *Handlers) Clear() {
|
||||||
|
h.Validate.Clear()
|
||||||
|
h.Build.Clear()
|
||||||
|
h.Send.Clear()
|
||||||
|
h.Sign.Clear()
|
||||||
|
h.Unmarshal.Clear()
|
||||||
|
h.UnmarshalMeta.Clear()
|
||||||
|
h.UnmarshalError.Clear()
|
||||||
|
h.ValidateResponse.Clear()
|
||||||
|
h.Retry.Clear()
|
||||||
|
h.AfterRetry.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
n.list = append([]NamedHandler{}, l.list...)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear clears the handler list.
|
||||||
|
func (l *HandlerList) Clear() {
|
||||||
|
l.list = []NamedHandler{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.list = append(l.list, NamedHandler{"__anonymous", f})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushFront pushes handler f to the front of the handler list.
|
||||||
|
func (l *HandlerList) PushFront(f func(*Request)) {
|
||||||
|
l.list = append([]NamedHandler{{"__anonymous", f}}, l.list...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushBackNamed pushes named handler f to the back of the handler list.
|
||||||
|
func (l *HandlerList) PushBackNamed(n NamedHandler) {
|
||||||
|
l.list = append(l.list, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushFrontNamed pushes named handler f to the front of the handler list.
|
||||||
|
func (l *HandlerList) PushFrontNamed(n NamedHandler) {
|
||||||
|
l.list = append([]NamedHandler{n}, l.list...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes a NamedHandler n
|
||||||
|
func (l *HandlerList) Remove(n NamedHandler) {
|
||||||
|
newlist := []NamedHandler{}
|
||||||
|
for _, m := range l.list {
|
||||||
|
if m.Name != n.Name {
|
||||||
|
newlist = append(newlist, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.list = newlist
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
24
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/http_request.go
generated
vendored
Normal file
24
vendor/github.com/hashicorp/go-discover/provider/aws/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
|
||||||
|
}
|
58
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader.go
generated
vendored
Normal file
58
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
reader := &offsetReader{}
|
||||||
|
buf.Seek(offset, 0)
|
||||||
|
|
||||||
|
reader.buf = buf
|
||||||
|
return reader
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
o.Close()
|
||||||
|
return newOffsetReader(o.buf, offset)
|
||||||
|
}
|
465
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/request.go
generated
vendored
Normal file
465
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/request.go
generated
vendored
Normal file
|
@ -0,0 +1,465 @@
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Request is the service request to be made.
|
||||||
|
type Request struct {
|
||||||
|
Config aws.Config
|
||||||
|
ClientInfo metadata.ClientInfo
|
||||||
|
Handlers Handlers
|
||||||
|
|
||||||
|
Retryer
|
||||||
|
Time time.Time
|
||||||
|
ExpireTime time.Duration
|
||||||
|
Operation *Operation
|
||||||
|
HTTPRequest *http.Request
|
||||||
|
HTTPResponse *http.Response
|
||||||
|
Body io.ReadSeeker
|
||||||
|
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
|
||||||
|
|
||||||
|
built bool
|
||||||
|
|
||||||
|
// Need to persist an intermideant body betweend 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 rewraps 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paginator keeps track of pagination configuration for an API operation.
|
||||||
|
type Paginator struct {
|
||||||
|
InputTokens []string
|
||||||
|
OutputTokens []string
|
||||||
|
LimitToken string
|
||||||
|
TruncationToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new Request pointer for the service API
|
||||||
|
// operation and parameters.
|
||||||
|
//
|
||||||
|
// 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 {
|
||||||
|
|
||||||
|
method := operation.HTTPMethod
|
||||||
|
if method == "" {
|
||||||
|
method = "POST"
|
||||||
|
}
|
||||||
|
|
||||||
|
httpReq, _ := http.NewRequest(method, "", nil)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
httpReq.URL, err = url.Parse(clientInfo.Endpoint + operation.HTTPPath)
|
||||||
|
if err != nil {
|
||||||
|
httpReq.URL = &url.URL{}
|
||||||
|
err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// WillRetry returns if the request's can be retried.
|
||||||
|
func (r *Request) WillRetry() bool {
|
||||||
|
return r.Error != nil && aws.BoolValue(r.Retryable) && r.RetryCount < r.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
|
||||||
|
r.ResetBody()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Presign returns the request's signed URL. Error will be returned
|
||||||
|
// if the signing fails.
|
||||||
|
func (r *Request) Presign(expireTime time.Duration) (string, error) {
|
||||||
|
r.ExpireTime = expireTime
|
||||||
|
r.NotHoist = false
|
||||||
|
|
||||||
|
if r.Operation.BeforePresignFn != nil {
|
||||||
|
r = r.copy()
|
||||||
|
err := r.Operation.BeforePresignFn(r)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Sign()
|
||||||
|
if r.Error != nil {
|
||||||
|
return "", r.Error
|
||||||
|
}
|
||||||
|
return r.HTTPRequest.URL.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PresignRequest behaves just like presign, but hoists all headers and signs them.
|
||||||
|
// Also returns the signed hash back to the user
|
||||||
|
func (r *Request) PresignRequest(expireTime time.Duration) (string, http.Header, error) {
|
||||||
|
r.ExpireTime = expireTime
|
||||||
|
r.NotHoist = true
|
||||||
|
r.Sign()
|
||||||
|
if r.Error != nil {
|
||||||
|
return "", nil, r.Error
|
||||||
|
}
|
||||||
|
return r.HTTPRequest.URL.String(), r.SignedHeaderVals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func debugLogReqError(r *Request, stage string, retrying bool, err error) {
|
||||||
|
if !r.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
retryStr := "not retrying"
|
||||||
|
if retrying {
|
||||||
|
retryStr = "will retry"
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
// Anny 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", false, r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
r.Handlers.Build.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
debugLogReqError(r, "Build Request", false, r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
r.built = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign will sign the request returning error if errors are encountered.
|
||||||
|
//
|
||||||
|
// Send 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", false, r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Handlers.Sign.Run(r)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetBody rewinds the request body backto its starting position, and
|
||||||
|
// set's the HTTP Request body reference. When the body is read prior
|
||||||
|
// to being sent in the HTTP request it will need to be rewound.
|
||||||
|
func (r *Request) ResetBody() {
|
||||||
|
if r.safeBody != nil {
|
||||||
|
r.safeBody.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
r.safeBody = newOffsetReader(r.Body, r.BodyStart)
|
||||||
|
|
||||||
|
// 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 := computeBodyLength(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed to compute request body size", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if l == 0 {
|
||||||
|
r.HTTPRequest.Body = noBodyReader
|
||||||
|
} else if l > 0 {
|
||||||
|
r.HTTPRequest.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.
|
||||||
|
switch r.Operation.HTTPMethod {
|
||||||
|
case "GET", "HEAD", "DELETE":
|
||||||
|
r.HTTPRequest.Body = noBodyReader
|
||||||
|
default:
|
||||||
|
r.HTTPRequest.Body = r.safeBody
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempts to compute the length of the body of the reader using the
|
||||||
|
// io.Seeker interface. If the value is not seekable because of being
|
||||||
|
// a ReaderSeekerCloser without an unerlying Seeker -1 will be returned.
|
||||||
|
// If no error occurs the length of the body will be returned.
|
||||||
|
func computeBodyLength(r io.ReadSeeker) (int64, error) {
|
||||||
|
seekable := true
|
||||||
|
// Determine if the seeker is actually seekable. ReaderSeekerCloser
|
||||||
|
// hides the fact that a io.Readers might not actually be seekable.
|
||||||
|
switch v := r.(type) {
|
||||||
|
case aws.ReaderSeekerCloser:
|
||||||
|
seekable = v.IsSeeker()
|
||||||
|
case *aws.ReaderSeekerCloser:
|
||||||
|
seekable = v.IsSeeker()
|
||||||
|
}
|
||||||
|
if !seekable {
|
||||||
|
return -1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
curOffset, err := r.Seek(0, 1)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endOffset, err := r.Seek(0, 2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.Seek(curOffset, 0)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return endOffset - curOffset, 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 {
|
||||||
|
for {
|
||||||
|
if aws.BoolValue(r.Retryable) {
|
||||||
|
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()
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Sign()
|
||||||
|
if r.Error != nil {
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Retryable = nil
|
||||||
|
|
||||||
|
r.Handlers.Send.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
if !shouldRetryCancel(r) {
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.Error
|
||||||
|
r.Handlers.Retry.Run(r)
|
||||||
|
r.Handlers.AfterRetry.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
debugLogReqError(r, "Send Request", false, r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
debugLogReqError(r, "Send Request", true, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r.Handlers.UnmarshalMeta.Run(r)
|
||||||
|
r.Handlers.ValidateResponse.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
err := r.Error
|
||||||
|
r.Handlers.UnmarshalError.Run(r)
|
||||||
|
r.Handlers.Retry.Run(r)
|
||||||
|
r.Handlers.AfterRetry.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
debugLogReqError(r, "Validate Response", false, r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
debugLogReqError(r, "Validate Response", true, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Handlers.Unmarshal.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
err := r.Error
|
||||||
|
r.Handlers.Retry.Run(r)
|
||||||
|
r.Handlers.AfterRetry.Run(r)
|
||||||
|
if r.Error != nil {
|
||||||
|
debugLogReqError(r, "Unmarshal Response", false, r.Error)
|
||||||
|
return r.Error
|
||||||
|
}
|
||||||
|
debugLogReqError(r, "Unmarshal Response", true, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldRetryCancel(r *Request) bool {
|
||||||
|
awsErr, ok := r.Error.(awserr.Error)
|
||||||
|
timeoutErr := false
|
||||||
|
errStr := r.Error.Error()
|
||||||
|
if ok {
|
||||||
|
err := awsErr.OrigErr()
|
||||||
|
netErr, netOK := err.(net.Error)
|
||||||
|
timeoutErr = netOK && netErr.Temporary()
|
||||||
|
if urlErr, ok := err.(*url.Error); !timeoutErr && ok {
|
||||||
|
errStr = urlErr.Err.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There can be two types of canceled errors here.
|
||||||
|
// The first being a net.Error and the other being an error.
|
||||||
|
// If the request was timed out, we want to continue the retry
|
||||||
|
// process. Otherwise, return the canceled error.
|
||||||
|
return timeoutErr ||
|
||||||
|
(errStr != "net/http: request canceled" &&
|
||||||
|
errStr != "net/http: request canceled while waiting for connection")
|
||||||
|
|
||||||
|
}
|
21
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7.go
generated
vendored
Normal file
21
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// +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 }
|
||||||
|
|
||||||
|
// Is an empty reader that will trigger the Go HTTP client to not include
|
||||||
|
// and body in the HTTP request.
|
||||||
|
var noBodyReader = noBody{}
|
9
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8.go
generated
vendored
Normal file
9
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// +build go1.8
|
||||||
|
|
||||||
|
package request
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// Is a http.NoBody reader instructing Go HTTP client to not include
|
||||||
|
// and body in the HTTP request.
|
||||||
|
var noBodyReader = http.NoBody
|
104
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination.go
generated
vendored
Normal file
104
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination.go
generated
vendored
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
//type Paginater interface {
|
||||||
|
// HasNextPage() bool
|
||||||
|
// NextPage() *Request
|
||||||
|
// EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error
|
||||||
|
//}
|
||||||
|
|
||||||
|
// HasNextPage returns true if this request has more pages of data available.
|
||||||
|
func (r *Request) HasNextPage() bool {
|
||||||
|
return len(r.nextPageTokens()) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 == false {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens := []interface{}{}
|
||||||
|
tokenAdded := false
|
||||||
|
for _, outToken := range r.Operation.OutputTokens {
|
||||||
|
v, _ := awsutil.ValuesAtPath(r.Data, outToken)
|
||||||
|
if len(v) > 0 {
|
||||||
|
tokens = append(tokens, v[0])
|
||||||
|
tokenAdded = true
|
||||||
|
} else {
|
||||||
|
tokens = append(tokens, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !tokenAdded {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (r *Request) NextPage() *Request {
|
||||||
|
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.
|
||||||
|
func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
|
||||||
|
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
|
||||||
|
}
|
102
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go
generated
vendored
Normal file
102
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go
generated
vendored
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Retryer is an interface to control retry logic for a given service.
|
||||||
|
// The default implementation used by most services is the service.DefaultRetryer
|
||||||
|
// structure, which contains basic retry logic using exponential backoff.
|
||||||
|
type Retryer interface {
|
||||||
|
RetryRules(*Request) time.Duration
|
||||||
|
ShouldRetry(*Request) bool
|
||||||
|
MaxRetries() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRetryer sets a config Retryer value to the given Config returning it
|
||||||
|
// for chaining.
|
||||||
|
func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
|
||||||
|
cfg.Retryer = retryer
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// retryableCodes is a collection of service response codes which are retry-able
|
||||||
|
// without any further action.
|
||||||
|
var retryableCodes = map[string]struct{}{
|
||||||
|
"RequestError": {},
|
||||||
|
"RequestTimeout": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
var throttleCodes = map[string]struct{}{
|
||||||
|
"ProvisionedThroughputExceededException": {},
|
||||||
|
"Throttling": {},
|
||||||
|
"ThrottlingException": {},
|
||||||
|
"RequestLimitExceeded": {},
|
||||||
|
"RequestThrottled": {},
|
||||||
|
"LimitExceededException": {}, // Deleting 10+ DynamoDb tables at once
|
||||||
|
"TooManyRequestsException": {}, // Lambda functions
|
||||||
|
"PriorRequestNotComplete": {}, // Route53
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrorRetryable returns whether the error is retryable, based on its Code.
|
||||||
|
// Returns false if the request has no Error set.
|
||||||
|
func (r *Request) IsErrorRetryable() bool {
|
||||||
|
if r.Error != nil {
|
||||||
|
if err, ok := r.Error.(awserr.Error); ok {
|
||||||
|
return isCodeRetryable(err.Code())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrorThrottle returns whether the error is to be throttled based on its code.
|
||||||
|
// Returns false if the request has no Error set
|
||||||
|
func (r *Request) IsErrorThrottle() bool {
|
||||||
|
if r.Error != nil {
|
||||||
|
if err, ok := r.Error.(awserr.Error); ok {
|
||||||
|
return isCodeThrottle(err.Code())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrorExpired returns whether the error code is a credential expiry error.
|
||||||
|
// Returns false if the request has no Error set.
|
||||||
|
func (r *Request) IsErrorExpired() bool {
|
||||||
|
if r.Error != nil {
|
||||||
|
if err, ok := r.Error.(awserr.Error); ok {
|
||||||
|
return isCodeExpiredCreds(err.Code())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
234
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/validation.go
generated
vendored
Normal file
234
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/request/validation.go
generated
vendored
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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: ParamMinValueErrCode,
|
||||||
|
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
|
||||||
|
}
|
223
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/session/doc.go
generated
vendored
Normal file
223
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/session/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
/*
|
||||||
|
Package session provides configuration for the SDK's service clients.
|
||||||
|
|
||||||
|
Sessions can be shared across all service clients that share the same base
|
||||||
|
configuration. The Session is built from the SDK's default configuration and
|
||||||
|
request handlers.
|
||||||
|
|
||||||
|
Sessions should be cached when possible, because creating a new Session will
|
||||||
|
load all configuration values from the environment, and config files each time
|
||||||
|
the Session is created. Sharing the Session value across all of your service
|
||||||
|
clients will ensure the configuration is loaded the fewest number of times possible.
|
||||||
|
|
||||||
|
Concurrency
|
||||||
|
|
||||||
|
Sessions are safe to use concurrently as long as the Session is not being
|
||||||
|
modified. The SDK will not modify the Session once the Session has been created.
|
||||||
|
Creating service clients concurrently from a shared Session is safe.
|
||||||
|
|
||||||
|
Sessions from Shared Config
|
||||||
|
|
||||||
|
Sessions can be created using the method above that will only load the
|
||||||
|
additional config if the AWS_SDK_LOAD_CONFIG environment variable is set.
|
||||||
|
Alternatively you can explicitly create a Session with shared config enabled.
|
||||||
|
To do this you can use NewSessionWithOptions to configure how the Session will
|
||||||
|
be created. Using the NewSessionWithOptions with SharedConfigState set to
|
||||||
|
SharedConfigEnabled will create the session as if the AWS_SDK_LOAD_CONFIG
|
||||||
|
environment variable was set.
|
||||||
|
|
||||||
|
Creating Sessions
|
||||||
|
|
||||||
|
When creating Sessions optional aws.Config values can be passed in that will
|
||||||
|
override the default, or loaded config values the Session is being created
|
||||||
|
with. This allows you to provide additional, or case based, configuration
|
||||||
|
as needed.
|
||||||
|
|
||||||
|
By default NewSession will only load credentials from the shared credentials
|
||||||
|
file (~/.aws/credentials). If the AWS_SDK_LOAD_CONFIG environment variable is
|
||||||
|
set to a truthy value the Session will be created from the configuration
|
||||||
|
values from the shared config (~/.aws/config) and shared credentials
|
||||||
|
(~/.aws/credentials) files. See the section Sessions from Shared Config for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
Create a Session with the default config and request handlers. With credentials
|
||||||
|
region, and profile loaded from the environment and shared config automatically.
|
||||||
|
Requires the AWS_PROFILE to be set, or "default" is used.
|
||||||
|
|
||||||
|
// Create Session
|
||||||
|
sess, err := session.NewSession()
|
||||||
|
|
||||||
|
// Create a Session with a custom region
|
||||||
|
sess, err := session.NewSession(&aws.Config{Region: aws.String("us-east-1")})
|
||||||
|
|
||||||
|
// Create a S3 client instance from a session
|
||||||
|
sess, err := session.NewSession()
|
||||||
|
if err != nil {
|
||||||
|
// Handle Session creation error
|
||||||
|
}
|
||||||
|
svc := s3.New(sess)
|
||||||
|
|
||||||
|
Create Session With Option Overrides
|
||||||
|
|
||||||
|
In addition to NewSession, Sessions can be created using NewSessionWithOptions.
|
||||||
|
This func allows you to control and override how the Session will be created
|
||||||
|
through code instead of being driven by environment variables only.
|
||||||
|
|
||||||
|
Use NewSessionWithOptions when you want to provide the config profile, or
|
||||||
|
override the shared config state (AWS_SDK_LOAD_CONFIG).
|
||||||
|
|
||||||
|
// Equivalent to session.NewSession()
|
||||||
|
sess, err := session.NewSessionWithOptions(session.Options{})
|
||||||
|
|
||||||
|
// Specify profile to load for the session's config
|
||||||
|
sess, err := session.NewSessionWithOptions(session.Options{
|
||||||
|
Profile: "profile_name",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Specify profile for config and region for requests
|
||||||
|
sess, err := session.NewSessionWithOptions(session.Options{
|
||||||
|
Config: aws.Config{Region: aws.String("us-east-1")},
|
||||||
|
Profile: "profile_name",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Force enable Shared Config support
|
||||||
|
sess, err := session.NewSessionWithOptions(session.Options{
|
||||||
|
SharedConfigState: SharedConfigEnable,
|
||||||
|
})
|
||||||
|
|
||||||
|
Adding Handlers
|
||||||
|
|
||||||
|
You can add handlers to a session for processing HTTP requests. All service
|
||||||
|
clients that use the session inherit the handlers. For example, the following
|
||||||
|
handler logs every request and its payload made by a service client:
|
||||||
|
|
||||||
|
// Create a session, and add additional handlers for all service
|
||||||
|
// clients created with the Session to inherit. Adds logging handler.
|
||||||
|
sess, err := session.NewSession()
|
||||||
|
sess.Handlers.Send.PushFront(func(r *request.Request) {
|
||||||
|
// Log every request made and its payload
|
||||||
|
logger.Println("Request: %s/%s, Payload: %s",
|
||||||
|
r.ClientInfo.ServiceName, r.Operation, r.Params)
|
||||||
|
})
|
||||||
|
|
||||||
|
Deprecated "New" function
|
||||||
|
|
||||||
|
The New session function has been deprecated because it does not provide good
|
||||||
|
way to return errors that occur when loading the configuration files and values.
|
||||||
|
Because of this, NewSession was created so errors can be retrieved when
|
||||||
|
creating a session fails.
|
||||||
|
|
||||||
|
Shared Config Fields
|
||||||
|
|
||||||
|
By default the SDK will only load the shared credentials file's (~/.aws/credentials)
|
||||||
|
credentials values, and all other config is provided by the environment variables,
|
||||||
|
SDK defaults, and user provided aws.Config values.
|
||||||
|
|
||||||
|
If the AWS_SDK_LOAD_CONFIG environment variable is set, or SharedConfigEnable
|
||||||
|
option is used to create the Session the full shared config values will be
|
||||||
|
loaded. This includes credentials, region, and support for assume role. In
|
||||||
|
addition the Session will load its configuration from both the shared config
|
||||||
|
file (~/.aws/config) and shared credentials file (~/.aws/credentials). Both
|
||||||
|
files have the same format.
|
||||||
|
|
||||||
|
If both config files are present the configuration from both files will be
|
||||||
|
read. The Session will be created from configuration values from the shared
|
||||||
|
credentials file (~/.aws/credentials) over those in the shared credentials
|
||||||
|
file (~/.aws/config).
|
||||||
|
|
||||||
|
Credentials are the values the SDK should use for authenticating requests with
|
||||||
|
AWS Services. They arfrom a configuration file will need to include both
|
||||||
|
aws_access_key_id and aws_secret_access_key must be provided together in the
|
||||||
|
same file to be considered valid. The values will be ignored if not a complete
|
||||||
|
group. aws_session_token is an optional field that can be provided if both of
|
||||||
|
the other two fields are also provided.
|
||||||
|
|
||||||
|
aws_access_key_id = AKID
|
||||||
|
aws_secret_access_key = SECRET
|
||||||
|
aws_session_token = TOKEN
|
||||||
|
|
||||||
|
Assume Role values allow you to configure the SDK to assume an IAM role using
|
||||||
|
a set of credentials provided in a config file via the source_profile field.
|
||||||
|
Both "role_arn" and "source_profile" are required. The SDK does not support
|
||||||
|
assuming a role with MFA token Via the Session's constructor. You can use the
|
||||||
|
stscreds.AssumeRoleProvider credentials provider to specify custom
|
||||||
|
configuration and support for MFA.
|
||||||
|
|
||||||
|
role_arn = arn:aws:iam::<account_number>:role/<role_name>
|
||||||
|
source_profile = profile_with_creds
|
||||||
|
external_id = 1234
|
||||||
|
mfa_serial = not supported!
|
||||||
|
role_session_name = session_name
|
||||||
|
|
||||||
|
Region is the region the SDK should use for looking up AWS service endpoints
|
||||||
|
and signing requests.
|
||||||
|
|
||||||
|
region = us-east-1
|
||||||
|
|
||||||
|
Environment Variables
|
||||||
|
|
||||||
|
When a Session is created several environment variables can be set to adjust
|
||||||
|
how the SDK functions, and what configuration data it loads when creating
|
||||||
|
Sessions. All environment values are optional, but some values like credentials
|
||||||
|
require multiple of the values to set or the partial values will be ignored.
|
||||||
|
All environment variable values are strings unless otherwise noted.
|
||||||
|
|
||||||
|
Environment configuration values. If set both Access Key ID and Secret Access
|
||||||
|
Key must be provided. Session Token and optionally also be provided, but is
|
||||||
|
not required.
|
||||||
|
|
||||||
|
# Access Key ID
|
||||||
|
AWS_ACCESS_KEY_ID=AKID
|
||||||
|
AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set.
|
||||||
|
|
||||||
|
# Secret Access Key
|
||||||
|
AWS_SECRET_ACCESS_KEY=SECRET
|
||||||
|
AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set.
|
||||||
|
|
||||||
|
# Session Token
|
||||||
|
AWS_SESSION_TOKEN=TOKEN
|
||||||
|
|
||||||
|
Region value will instruct the SDK where to make service API requests to. If is
|
||||||
|
not provided in the environment the region must be provided before a service
|
||||||
|
client request is made.
|
||||||
|
|
||||||
|
AWS_REGION=us-east-1
|
||||||
|
|
||||||
|
# AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||||
|
# and AWS_REGION is not also set.
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
|
||||||
|
Profile name the SDK should load use when loading shared config from the
|
||||||
|
configuration files. If not provided "default" will be used as the profile name.
|
||||||
|
|
||||||
|
AWS_PROFILE=my_profile
|
||||||
|
|
||||||
|
# AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||||
|
# and AWS_PROFILE is not also set.
|
||||||
|
AWS_DEFAULT_PROFILE=my_profile
|
||||||
|
|
||||||
|
SDK load config instructs the SDK to load the shared config in addition to
|
||||||
|
shared credentials. This also expands the configuration loaded so the shared
|
||||||
|
credentials will have parity with the shared config file. This also enables
|
||||||
|
Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE
|
||||||
|
env values as well.
|
||||||
|
|
||||||
|
AWS_SDK_LOAD_CONFIG=1
|
||||||
|
|
||||||
|
Shared credentials file path can be set to instruct the SDK to use an alternative
|
||||||
|
file for the shared credentials. If not set the file will be loaded from
|
||||||
|
$HOME/.aws/credentials on Linux/Unix based systems, and
|
||||||
|
%USERPROFILE%\.aws\credentials on Windows.
|
||||||
|
|
||||||
|
AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials
|
||||||
|
|
||||||
|
Shared config file path can be set to instruct the SDK to use an alternative
|
||||||
|
file for the shared config. If not set the file will be loaded from
|
||||||
|
$HOME/.aws/config on Linux/Unix based systems, and
|
||||||
|
%USERPROFILE%\.aws\config on Windows.
|
||||||
|
|
||||||
|
AWS_CONFIG_FILE=$HOME/my_shared_config
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
package session
|
188
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/session/env_config.go
generated
vendored
Normal file
188
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/session/env_config.go
generated
vendored
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
// envConfig is a collection of environment values the SDK will read
|
||||||
|
// setup config from. All environment values are optional. But some values
|
||||||
|
// such as credentials require multiple values to be complete or the values
|
||||||
|
// will be ignored.
|
||||||
|
type envConfig struct {
|
||||||
|
// Environment configuration values. If set both Access Key ID and Secret Access
|
||||||
|
// Key must be provided. Session Token and optionally also be provided, but is
|
||||||
|
// not required.
|
||||||
|
//
|
||||||
|
// # Access Key ID
|
||||||
|
// AWS_ACCESS_KEY_ID=AKID
|
||||||
|
// AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set.
|
||||||
|
//
|
||||||
|
// # Secret Access Key
|
||||||
|
// AWS_SECRET_ACCESS_KEY=SECRET
|
||||||
|
// AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set.
|
||||||
|
//
|
||||||
|
// # Session Token
|
||||||
|
// AWS_SESSION_TOKEN=TOKEN
|
||||||
|
Creds credentials.Value
|
||||||
|
|
||||||
|
// Region value will instruct the SDK where to make service API requests to. If is
|
||||||
|
// not provided in the environment the region must be provided before a service
|
||||||
|
// client request is made.
|
||||||
|
//
|
||||||
|
// AWS_REGION=us-east-1
|
||||||
|
//
|
||||||
|
// # AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||||
|
// # and AWS_REGION is not also set.
|
||||||
|
// AWS_DEFAULT_REGION=us-east-1
|
||||||
|
Region string
|
||||||
|
|
||||||
|
// Profile name the SDK should load use when loading shared configuration from the
|
||||||
|
// shared configuration files. If not provided "default" will be used as the
|
||||||
|
// profile name.
|
||||||
|
//
|
||||||
|
// AWS_PROFILE=my_profile
|
||||||
|
//
|
||||||
|
// # AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||||
|
// # and AWS_PROFILE is not also set.
|
||||||
|
// AWS_DEFAULT_PROFILE=my_profile
|
||||||
|
Profile string
|
||||||
|
|
||||||
|
// SDK load config instructs the SDK to load the shared config in addition to
|
||||||
|
// shared credentials. This also expands the configuration loaded from the shared
|
||||||
|
// credentials to have parity with the shared config file. This also enables
|
||||||
|
// Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE
|
||||||
|
// env values as well.
|
||||||
|
//
|
||||||
|
// AWS_SDK_LOAD_CONFIG=1
|
||||||
|
EnableSharedConfig bool
|
||||||
|
|
||||||
|
// Shared credentials file path can be set to instruct the SDK to use an alternate
|
||||||
|
// file for the shared credentials. If not set the file will be loaded from
|
||||||
|
// $HOME/.aws/credentials on Linux/Unix based systems, and
|
||||||
|
// %USERPROFILE%\.aws\credentials on Windows.
|
||||||
|
//
|
||||||
|
// AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials
|
||||||
|
SharedCredentialsFile string
|
||||||
|
|
||||||
|
// Shared config file path can be set to instruct the SDK to use an alternate
|
||||||
|
// file for the shared config. If not set the file will be loaded from
|
||||||
|
// $HOME/.aws/config on Linux/Unix based systems, and
|
||||||
|
// %USERPROFILE%\.aws\config on Windows.
|
||||||
|
//
|
||||||
|
// AWS_CONFIG_FILE=$HOME/my_shared_config
|
||||||
|
SharedConfigFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
credAccessEnvKey = []string{
|
||||||
|
"AWS_ACCESS_KEY_ID",
|
||||||
|
"AWS_ACCESS_KEY",
|
||||||
|
}
|
||||||
|
credSecretEnvKey = []string{
|
||||||
|
"AWS_SECRET_ACCESS_KEY",
|
||||||
|
"AWS_SECRET_KEY",
|
||||||
|
}
|
||||||
|
credSessionEnvKey = []string{
|
||||||
|
"AWS_SESSION_TOKEN",
|
||||||
|
}
|
||||||
|
|
||||||
|
regionEnvKeys = []string{
|
||||||
|
"AWS_REGION",
|
||||||
|
"AWS_DEFAULT_REGION", // Only read if AWS_SDK_LOAD_CONFIG is also set
|
||||||
|
}
|
||||||
|
profileEnvKeys = []string{
|
||||||
|
"AWS_PROFILE",
|
||||||
|
"AWS_DEFAULT_PROFILE", // Only read if AWS_SDK_LOAD_CONFIG is also set
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// loadEnvConfig retrieves the SDK's environment configuration.
|
||||||
|
// See `envConfig` for the values that will be retrieved.
|
||||||
|
//
|
||||||
|
// If the environment variable `AWS_SDK_LOAD_CONFIG` is set to a truthy value
|
||||||
|
// the shared SDK config will be loaded in addition to the SDK's specific
|
||||||
|
// configuration values.
|
||||||
|
func loadEnvConfig() envConfig {
|
||||||
|
enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG"))
|
||||||
|
return envConfigLoad(enableSharedConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadEnvSharedConfig retrieves the SDK's environment configuration, and the
|
||||||
|
// SDK shared config. See `envConfig` for the values that will be retrieved.
|
||||||
|
//
|
||||||
|
// Loads the shared configuration in addition to the SDK's specific configuration.
|
||||||
|
// This will load the same values as `loadEnvConfig` if the `AWS_SDK_LOAD_CONFIG`
|
||||||
|
// environment variable is set.
|
||||||
|
func loadSharedEnvConfig() envConfig {
|
||||||
|
return envConfigLoad(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func envConfigLoad(enableSharedConfig bool) envConfig {
|
||||||
|
cfg := envConfig{}
|
||||||
|
|
||||||
|
cfg.EnableSharedConfig = enableSharedConfig
|
||||||
|
|
||||||
|
setFromEnvVal(&cfg.Creds.AccessKeyID, credAccessEnvKey)
|
||||||
|
setFromEnvVal(&cfg.Creds.SecretAccessKey, credSecretEnvKey)
|
||||||
|
setFromEnvVal(&cfg.Creds.SessionToken, credSessionEnvKey)
|
||||||
|
|
||||||
|
// Require logical grouping of credentials
|
||||||
|
if len(cfg.Creds.AccessKeyID) == 0 || len(cfg.Creds.SecretAccessKey) == 0 {
|
||||||
|
cfg.Creds = credentials.Value{}
|
||||||
|
} else {
|
||||||
|
cfg.Creds.ProviderName = "EnvConfigCredentials"
|
||||||
|
}
|
||||||
|
|
||||||
|
regionKeys := regionEnvKeys
|
||||||
|
profileKeys := profileEnvKeys
|
||||||
|
if !cfg.EnableSharedConfig {
|
||||||
|
regionKeys = regionKeys[:1]
|
||||||
|
profileKeys = profileKeys[:1]
|
||||||
|
}
|
||||||
|
|
||||||
|
setFromEnvVal(&cfg.Region, regionKeys)
|
||||||
|
setFromEnvVal(&cfg.Profile, profileKeys)
|
||||||
|
|
||||||
|
cfg.SharedCredentialsFile = sharedCredentialsFilename()
|
||||||
|
cfg.SharedConfigFile = sharedConfigFilename()
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFromEnvVal(dst *string, keys []string) {
|
||||||
|
for _, k := range keys {
|
||||||
|
if v := os.Getenv(k); len(v) > 0 {
|
||||||
|
*dst = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sharedCredentialsFilename() string {
|
||||||
|
if name := os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); len(name) > 0 {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Join(userHomeDir(), ".aws", "credentials")
|
||||||
|
}
|
||||||
|
|
||||||
|
func sharedConfigFilename() string {
|
||||||
|
if name := os.Getenv("AWS_CONFIG_FILE"); len(name) > 0 {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Join(userHomeDir(), ".aws", "config")
|
||||||
|
}
|
||||||
|
|
||||||
|
func userHomeDir() string {
|
||||||
|
homeDir := os.Getenv("HOME") // *nix
|
||||||
|
if len(homeDir) == 0 { // windows
|
||||||
|
homeDir = os.Getenv("USERPROFILE")
|
||||||
|
}
|
||||||
|
|
||||||
|
return homeDir
|
||||||
|
}
|
446
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/session/session.go
generated
vendored
Normal file
446
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/session/session.go
generated
vendored
Normal file
|
@ -0,0 +1,446 @@
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"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/corehandlers"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Session provides a central location to create service clients from and
|
||||||
|
// store configurations and request handlers for those services.
|
||||||
|
//
|
||||||
|
// Sessions are safe to create service clients concurrently, but it is not safe
|
||||||
|
// to mutate the Session concurrently.
|
||||||
|
//
|
||||||
|
// The Session satisfies the service client's client.ClientConfigProvider.
|
||||||
|
type Session struct {
|
||||||
|
Config *aws.Config
|
||||||
|
Handlers request.Handlers
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new instance of the handlers merging in the provided configs
|
||||||
|
// on top of the SDK's default configurations. Once the Session is created it
|
||||||
|
// can be mutated to modify the Config or Handlers. The Session is safe to be
|
||||||
|
// read concurrently, but it should not be written to concurrently.
|
||||||
|
//
|
||||||
|
// If the AWS_SDK_LOAD_CONFIG environment is set to a truthy value, the New
|
||||||
|
// method could now encounter an error when loading the configuration. When
|
||||||
|
// The environment variable is set, and an error occurs, New will return a
|
||||||
|
// session that will fail all requests reporting the error that occurred while
|
||||||
|
// loading the session. Use NewSession to get the error when creating the
|
||||||
|
// session.
|
||||||
|
//
|
||||||
|
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||||
|
// the shared config file (~/.aws/config) will also be loaded, in addition to
|
||||||
|
// the shared credentials file (~/.aws/credentials). Values set in both the
|
||||||
|
// shared config, and shared credentials will be taken from the shared
|
||||||
|
// credentials file.
|
||||||
|
//
|
||||||
|
// Deprecated: Use NewSession functions to create sessions instead. NewSession
|
||||||
|
// has the same functionality as New except an error can be returned when the
|
||||||
|
// func is called instead of waiting to receive an error until a request is made.
|
||||||
|
func New(cfgs ...*aws.Config) *Session {
|
||||||
|
// load initial config from environment
|
||||||
|
envCfg := loadEnvConfig()
|
||||||
|
|
||||||
|
if envCfg.EnableSharedConfig {
|
||||||
|
s, err := newSession(envCfg, cfgs...)
|
||||||
|
if err != nil {
|
||||||
|
// Old session.New expected all errors to be discovered when
|
||||||
|
// a request is made, and would report the errors then. This
|
||||||
|
// needs to be replicated if an error occurs while creating
|
||||||
|
// the session.
|
||||||
|
msg := "failed to create session with AWS_SDK_LOAD_CONFIG enabled. " +
|
||||||
|
"Use session.NewSession to handle errors occurring during session creation."
|
||||||
|
|
||||||
|
// Session creation failed, need to report the error and prevent
|
||||||
|
// any requests from succeeding.
|
||||||
|
s = &Session{Config: defaults.Config()}
|
||||||
|
s.Config.MergeIn(cfgs...)
|
||||||
|
s.Config.Logger.Log("ERROR:", msg, "Error:", err)
|
||||||
|
s.Handlers.Validate.PushBack(func(r *request.Request) {
|
||||||
|
r.Error = err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldNewSession(cfgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSession returns a new Session created from SDK defaults, config files,
|
||||||
|
// environment, and user provided config files. Once the Session is created
|
||||||
|
// it can be mutated to modify the Config or Handlers. The Session is safe to
|
||||||
|
// be read concurrently, but it should not be written to concurrently.
|
||||||
|
//
|
||||||
|
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||||
|
// the shared config file (~/.aws/config) will also be loaded in addition to
|
||||||
|
// the shared credentials file (~/.aws/credentials). Values set in both the
|
||||||
|
// shared config, and shared credentials will be taken from the shared
|
||||||
|
// credentials file. Enabling the Shared Config will also allow the Session
|
||||||
|
// to be built with retrieving credentials with AssumeRole set in the config.
|
||||||
|
//
|
||||||
|
// See the NewSessionWithOptions func for information on how to override or
|
||||||
|
// control through code how the Session will be created. Such as specifying the
|
||||||
|
// config profile, and controlling if shared config is enabled or not.
|
||||||
|
func NewSession(cfgs ...*aws.Config) (*Session, error) {
|
||||||
|
envCfg := loadEnvConfig()
|
||||||
|
|
||||||
|
return newSession(envCfg, cfgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SharedConfigState provides the ability to optionally override the state
|
||||||
|
// of the session's creation based on the shared config being enabled or
|
||||||
|
// disabled.
|
||||||
|
type SharedConfigState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SharedConfigStateFromEnv does not override any state of the
|
||||||
|
// AWS_SDK_LOAD_CONFIG env var. It is the default value of the
|
||||||
|
// SharedConfigState type.
|
||||||
|
SharedConfigStateFromEnv SharedConfigState = iota
|
||||||
|
|
||||||
|
// SharedConfigDisable overrides the AWS_SDK_LOAD_CONFIG env var value
|
||||||
|
// and disables the shared config functionality.
|
||||||
|
SharedConfigDisable
|
||||||
|
|
||||||
|
// SharedConfigEnable overrides the AWS_SDK_LOAD_CONFIG env var value
|
||||||
|
// and enables the shared config functionality.
|
||||||
|
SharedConfigEnable
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options provides the means to control how a Session is created and what
|
||||||
|
// configuration values will be loaded.
|
||||||
|
//
|
||||||
|
type Options struct {
|
||||||
|
// Provides config values for the SDK to use when creating service clients
|
||||||
|
// and making API requests to services. Any value set in with this field
|
||||||
|
// will override the associated value provided by the SDK defaults,
|
||||||
|
// environment or config files where relevant.
|
||||||
|
//
|
||||||
|
// If not set, configuration values from from SDK defaults, environment,
|
||||||
|
// config will be used.
|
||||||
|
Config aws.Config
|
||||||
|
|
||||||
|
// Overrides the config profile the Session should be created from. If not
|
||||||
|
// set the value of the environment variable will be loaded (AWS_PROFILE,
|
||||||
|
// or AWS_DEFAULT_PROFILE if the Shared Config is enabled).
|
||||||
|
//
|
||||||
|
// If not set and environment variables are not set the "default"
|
||||||
|
// (DefaultSharedConfigProfile) will be used as the profile to load the
|
||||||
|
// session config from.
|
||||||
|
Profile string
|
||||||
|
|
||||||
|
// Instructs how the Session will be created based on the AWS_SDK_LOAD_CONFIG
|
||||||
|
// environment variable. By default a Session will be created using the
|
||||||
|
// value provided by the AWS_SDK_LOAD_CONFIG environment variable.
|
||||||
|
//
|
||||||
|
// Setting this value to SharedConfigEnable or SharedConfigDisable
|
||||||
|
// will allow you to override the AWS_SDK_LOAD_CONFIG environment variable
|
||||||
|
// and enable or disable the shared config functionality.
|
||||||
|
SharedConfigState SharedConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSessionWithOptions returns a new Session created from SDK defaults, config files,
|
||||||
|
// environment, and user provided config files. This func uses the Options
|
||||||
|
// values to configure how the Session is created.
|
||||||
|
//
|
||||||
|
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||||
|
// the shared config file (~/.aws/config) will also be loaded in addition to
|
||||||
|
// the shared credentials file (~/.aws/credentials). Values set in both the
|
||||||
|
// shared config, and shared credentials will be taken from the shared
|
||||||
|
// credentials file. Enabling the Shared Config will also allow the Session
|
||||||
|
// to be built with retrieving credentials with AssumeRole set in the config.
|
||||||
|
//
|
||||||
|
// // Equivalent to session.New
|
||||||
|
// sess, err := session.NewSessionWithOptions(session.Options{})
|
||||||
|
//
|
||||||
|
// // Specify profile to load for the session's config
|
||||||
|
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||||
|
// Profile: "profile_name",
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// // Specify profile for config and region for requests
|
||||||
|
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||||
|
// Config: aws.Config{Region: aws.String("us-east-1")},
|
||||||
|
// Profile: "profile_name",
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// // Force enable Shared Config support
|
||||||
|
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||||
|
// SharedConfigState: SharedConfigEnable,
|
||||||
|
// })
|
||||||
|
func NewSessionWithOptions(opts Options) (*Session, error) {
|
||||||
|
var envCfg envConfig
|
||||||
|
if opts.SharedConfigState == SharedConfigEnable {
|
||||||
|
envCfg = loadSharedEnvConfig()
|
||||||
|
} else {
|
||||||
|
envCfg = loadEnvConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts.Profile) > 0 {
|
||||||
|
envCfg.Profile = opts.Profile
|
||||||
|
}
|
||||||
|
|
||||||
|
switch opts.SharedConfigState {
|
||||||
|
case SharedConfigDisable:
|
||||||
|
envCfg.EnableSharedConfig = false
|
||||||
|
case SharedConfigEnable:
|
||||||
|
envCfg.EnableSharedConfig = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return newSession(envCfg, &opts.Config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must is a helper function to ensure the Session is valid and there was no
|
||||||
|
// error when calling a NewSession function.
|
||||||
|
//
|
||||||
|
// This helper is intended to be used in variable initialization to load the
|
||||||
|
// Session and configuration at startup. Such as:
|
||||||
|
//
|
||||||
|
// var sess = session.Must(session.NewSession())
|
||||||
|
func Must(sess *Session, err error) *Session {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sess
|
||||||
|
}
|
||||||
|
|
||||||
|
func oldNewSession(cfgs ...*aws.Config) *Session {
|
||||||
|
cfg := defaults.Config()
|
||||||
|
handlers := defaults.Handlers()
|
||||||
|
|
||||||
|
// Apply the passed in configs so the configuration can be applied to the
|
||||||
|
// default credential chain
|
||||||
|
cfg.MergeIn(cfgs...)
|
||||||
|
if cfg.EndpointResolver == nil {
|
||||||
|
// An endpoint resolver is required for a session to be able to provide
|
||||||
|
// endpoints for service client configurations.
|
||||||
|
cfg.EndpointResolver = endpoints.DefaultResolver()
|
||||||
|
}
|
||||||
|
cfg.Credentials = defaults.CredChain(cfg, handlers)
|
||||||
|
|
||||||
|
// Reapply any passed in configs to override credentials if set
|
||||||
|
cfg.MergeIn(cfgs...)
|
||||||
|
|
||||||
|
s := &Session{
|
||||||
|
Config: cfg,
|
||||||
|
Handlers: handlers,
|
||||||
|
}
|
||||||
|
|
||||||
|
initHandlers(s)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSession(envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
|
||||||
|
cfg := defaults.Config()
|
||||||
|
handlers := defaults.Handlers()
|
||||||
|
|
||||||
|
// Get a merged version of the user provided config to determine if
|
||||||
|
// credentials were.
|
||||||
|
userCfg := &aws.Config{}
|
||||||
|
userCfg.MergeIn(cfgs...)
|
||||||
|
|
||||||
|
// Order config files will be loaded in with later files overwriting
|
||||||
|
// previous config file values.
|
||||||
|
cfgFiles := []string{envCfg.SharedConfigFile, envCfg.SharedCredentialsFile}
|
||||||
|
if !envCfg.EnableSharedConfig {
|
||||||
|
// The shared config file (~/.aws/config) is only loaded if instructed
|
||||||
|
// to load via the envConfig.EnableSharedConfig (AWS_SDK_LOAD_CONFIG).
|
||||||
|
cfgFiles = cfgFiles[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load additional config from file(s)
|
||||||
|
sharedCfg, err := loadSharedConfig(envCfg.Profile, cfgFiles)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers)
|
||||||
|
|
||||||
|
s := &Session{
|
||||||
|
Config: cfg,
|
||||||
|
Handlers: handlers,
|
||||||
|
}
|
||||||
|
|
||||||
|
initHandlers(s)
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg sharedConfig, handlers request.Handlers) {
|
||||||
|
// Merge in user provided configuration
|
||||||
|
cfg.MergeIn(userCfg)
|
||||||
|
|
||||||
|
// Region if not already set by user
|
||||||
|
if len(aws.StringValue(cfg.Region)) == 0 {
|
||||||
|
if len(envCfg.Region) > 0 {
|
||||||
|
cfg.WithRegion(envCfg.Region)
|
||||||
|
} else if envCfg.EnableSharedConfig && len(sharedCfg.Region) > 0 {
|
||||||
|
cfg.WithRegion(sharedCfg.Region)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure credentials if not already set
|
||||||
|
if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil {
|
||||||
|
if len(envCfg.Creds.AccessKeyID) > 0 {
|
||||||
|
cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
|
||||||
|
envCfg.Creds,
|
||||||
|
)
|
||||||
|
} else if envCfg.EnableSharedConfig && len(sharedCfg.AssumeRole.RoleARN) > 0 && sharedCfg.AssumeRoleSource != nil {
|
||||||
|
cfgCp := *cfg
|
||||||
|
cfgCp.Credentials = credentials.NewStaticCredentialsFromCreds(
|
||||||
|
sharedCfg.AssumeRoleSource.Creds,
|
||||||
|
)
|
||||||
|
cfg.Credentials = stscreds.NewCredentials(
|
||||||
|
&Session{
|
||||||
|
Config: &cfgCp,
|
||||||
|
Handlers: handlers.Copy(),
|
||||||
|
},
|
||||||
|
sharedCfg.AssumeRole.RoleARN,
|
||||||
|
func(opt *stscreds.AssumeRoleProvider) {
|
||||||
|
opt.RoleSessionName = sharedCfg.AssumeRole.RoleSessionName
|
||||||
|
|
||||||
|
if len(sharedCfg.AssumeRole.ExternalID) > 0 {
|
||||||
|
opt.ExternalID = aws.String(sharedCfg.AssumeRole.ExternalID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MFA not supported
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else if len(sharedCfg.Creds.AccessKeyID) > 0 {
|
||||||
|
cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
|
||||||
|
sharedCfg.Creds,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Fallback to default credentials provider, include mock errors
|
||||||
|
// for the credential chain so user can identify why credentials
|
||||||
|
// failed to be retrieved.
|
||||||
|
cfg.Credentials = 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),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type credProviderError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
var emptyCreds = credentials.Value{}
|
||||||
|
|
||||||
|
func (c credProviderError) Retrieve() (credentials.Value, error) {
|
||||||
|
return credentials.Value{}, c.Err
|
||||||
|
}
|
||||||
|
func (c credProviderError) IsExpired() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func initHandlers(s *Session) {
|
||||||
|
// Add the Validate parameter handler if it is not disabled.
|
||||||
|
s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
|
||||||
|
if !aws.BoolValue(s.Config.DisableParamValidation) {
|
||||||
|
s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy creates and returns a copy of the current Session, coping the config
|
||||||
|
// and handlers. If any additional configs are provided they will be merged
|
||||||
|
// on top of the Session's copied config.
|
||||||
|
//
|
||||||
|
// // Create a copy of the current Session, configured for the us-west-2 region.
|
||||||
|
// sess.Copy(&aws.Config{Region: aws.String("us-west-2")})
|
||||||
|
func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
||||||
|
newSession := &Session{
|
||||||
|
Config: s.Config.Copy(cfgs...),
|
||||||
|
Handlers: s.Handlers.Copy(),
|
||||||
|
}
|
||||||
|
|
||||||
|
initHandlers(newSession)
|
||||||
|
|
||||||
|
return newSession
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientConfig satisfies the client.ConfigProvider interface and is used to
|
||||||
|
// configure the service client instances. Passing the Session to the service
|
||||||
|
// client's constructor (New) will use this method to configure the client.
|
||||||
|
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
|
||||||
|
// Backwards compatibility, the error will be eaten if user calls ClientConfig
|
||||||
|
// directly. All SDK services will use ClientconfigWithError.
|
||||||
|
cfg, _ := s.clientConfigWithErr(serviceName, cfgs...)
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) clientConfigWithErr(serviceName string, cfgs ...*aws.Config) (client.Config, error) {
|
||||||
|
s = s.Copy(cfgs...)
|
||||||
|
|
||||||
|
var resolved endpoints.ResolvedEndpoint
|
||||||
|
var err error
|
||||||
|
|
||||||
|
region := aws.StringValue(s.Config.Region)
|
||||||
|
|
||||||
|
if endpoint := aws.StringValue(s.Config.Endpoint); len(endpoint) != 0 {
|
||||||
|
resolved.URL = endpoints.AddScheme(endpoint, aws.BoolValue(s.Config.DisableSSL))
|
||||||
|
resolved.SigningRegion = region
|
||||||
|
} else {
|
||||||
|
resolved, err = s.Config.EndpointResolver.EndpointFor(
|
||||||
|
serviceName, region,
|
||||||
|
func(opt *endpoints.Options) {
|
||||||
|
opt.DisableSSL = aws.BoolValue(s.Config.DisableSSL)
|
||||||
|
opt.UseDualStack = aws.BoolValue(s.Config.UseDualStack)
|
||||||
|
|
||||||
|
// Support the condition where the service is modeled but its
|
||||||
|
// endpoint metadata is not available.
|
||||||
|
opt.ResolveUnknownService = true
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Config{
|
||||||
|
Config: s.Config,
|
||||||
|
Handlers: s.Handlers,
|
||||||
|
Endpoint: resolved.URL,
|
||||||
|
SigningRegion: resolved.SigningRegion,
|
||||||
|
SigningName: resolved.SigningName,
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception
|
||||||
|
// that the EndpointResolver will not be used to resolve the endpoint. The only
|
||||||
|
// endpoint set must come from the aws.Config.Endpoint field.
|
||||||
|
func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Config {
|
||||||
|
s = s.Copy(cfgs...)
|
||||||
|
|
||||||
|
var resolved endpoints.ResolvedEndpoint
|
||||||
|
|
||||||
|
region := aws.StringValue(s.Config.Region)
|
||||||
|
|
||||||
|
if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 {
|
||||||
|
resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL))
|
||||||
|
resolved.SigningRegion = region
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Config{
|
||||||
|
Config: s.Config,
|
||||||
|
Handlers: s.Handlers,
|
||||||
|
Endpoint: resolved.URL,
|
||||||
|
SigningRegion: resolved.SigningRegion,
|
||||||
|
SigningName: resolved.SigningName,
|
||||||
|
}
|
||||||
|
}
|
295
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go
generated
vendored
Normal file
295
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go
generated
vendored
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/go-ini/ini"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Static Credentials group
|
||||||
|
accessKeyIDKey = `aws_access_key_id` // group required
|
||||||
|
secretAccessKey = `aws_secret_access_key` // group required
|
||||||
|
sessionTokenKey = `aws_session_token` // optional
|
||||||
|
|
||||||
|
// Assume Role Credentials group
|
||||||
|
roleArnKey = `role_arn` // group required
|
||||||
|
sourceProfileKey = `source_profile` // group required
|
||||||
|
externalIDKey = `external_id` // optional
|
||||||
|
mfaSerialKey = `mfa_serial` // optional
|
||||||
|
roleSessionNameKey = `role_session_name` // optional
|
||||||
|
|
||||||
|
// Additional Config fields
|
||||||
|
regionKey = `region`
|
||||||
|
|
||||||
|
// DefaultSharedConfigProfile is the default profile to be used when
|
||||||
|
// loading configuration from the config files if another profile name
|
||||||
|
// is not provided.
|
||||||
|
DefaultSharedConfigProfile = `default`
|
||||||
|
)
|
||||||
|
|
||||||
|
type assumeRoleConfig struct {
|
||||||
|
RoleARN string
|
||||||
|
SourceProfile string
|
||||||
|
ExternalID string
|
||||||
|
MFASerial string
|
||||||
|
RoleSessionName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// sharedConfig represents the configuration fields of the SDK config files.
|
||||||
|
type sharedConfig struct {
|
||||||
|
// Credentials values from the config file. Both aws_access_key_id
|
||||||
|
// and aws_secret_access_key must be provided together in the same file
|
||||||
|
// to be considered valid. The values will be ignored if not a complete group.
|
||||||
|
// aws_session_token is an optional field that can be provided if both of the
|
||||||
|
// other two fields are also provided.
|
||||||
|
//
|
||||||
|
// aws_access_key_id
|
||||||
|
// aws_secret_access_key
|
||||||
|
// aws_session_token
|
||||||
|
Creds credentials.Value
|
||||||
|
|
||||||
|
AssumeRole assumeRoleConfig
|
||||||
|
AssumeRoleSource *sharedConfig
|
||||||
|
|
||||||
|
// Region is the region the SDK should use for looking up AWS service endpoints
|
||||||
|
// and signing requests.
|
||||||
|
//
|
||||||
|
// region
|
||||||
|
Region string
|
||||||
|
}
|
||||||
|
|
||||||
|
type sharedConfigFile struct {
|
||||||
|
Filename string
|
||||||
|
IniData *ini.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadSharedConfig retrieves the configuration from the list of files
|
||||||
|
// using the profile provided. The order the files are listed will determine
|
||||||
|
// precedence. Values in subsequent files will overwrite values defined in
|
||||||
|
// earlier files.
|
||||||
|
//
|
||||||
|
// For example, given two files A and B. Both define credentials. If the order
|
||||||
|
// of the files are A then B, B's credential values will be used instead of A's.
|
||||||
|
//
|
||||||
|
// See sharedConfig.setFromFile for information how the config files
|
||||||
|
// will be loaded.
|
||||||
|
func loadSharedConfig(profile string, filenames []string) (sharedConfig, error) {
|
||||||
|
if len(profile) == 0 {
|
||||||
|
profile = DefaultSharedConfigProfile
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := loadSharedConfigIniFiles(filenames)
|
||||||
|
if err != nil {
|
||||||
|
return sharedConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := sharedConfig{}
|
||||||
|
if err = cfg.setFromIniFiles(profile, files); err != nil {
|
||||||
|
return sharedConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cfg.AssumeRole.SourceProfile) > 0 {
|
||||||
|
if err := cfg.setAssumeRoleSource(profile, files); err != nil {
|
||||||
|
return sharedConfig{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadSharedConfigIniFiles(filenames []string) ([]sharedConfigFile, error) {
|
||||||
|
files := make([]sharedConfigFile, 0, len(filenames))
|
||||||
|
|
||||||
|
for _, filename := range filenames {
|
||||||
|
b, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
// Skip files which can't be opened and read for whatever reason
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := ini.Load(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, SharedConfigLoadError{Filename: filename}
|
||||||
|
}
|
||||||
|
|
||||||
|
files = append(files, sharedConfigFile{
|
||||||
|
Filename: filename, IniData: f,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *sharedConfig) setAssumeRoleSource(origProfile string, files []sharedConfigFile) error {
|
||||||
|
var assumeRoleSrc sharedConfig
|
||||||
|
|
||||||
|
// Multiple level assume role chains are not support
|
||||||
|
if cfg.AssumeRole.SourceProfile == origProfile {
|
||||||
|
assumeRoleSrc = *cfg
|
||||||
|
assumeRoleSrc.AssumeRole = assumeRoleConfig{}
|
||||||
|
} else {
|
||||||
|
err := assumeRoleSrc.setFromIniFiles(cfg.AssumeRole.SourceProfile, files)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(assumeRoleSrc.Creds.AccessKeyID) == 0 {
|
||||||
|
return SharedConfigAssumeRoleError{RoleARN: cfg.AssumeRole.RoleARN}
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.AssumeRoleSource = &assumeRoleSrc
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *sharedConfig) setFromIniFiles(profile string, files []sharedConfigFile) error {
|
||||||
|
// Trim files from the list that don't exist.
|
||||||
|
for _, f := range files {
|
||||||
|
if err := cfg.setFromIniFile(profile, f); err != nil {
|
||||||
|
if _, ok := err.(SharedConfigProfileNotExistsError); ok {
|
||||||
|
// Ignore proviles missings
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setFromFile loads the configuration from the file using
|
||||||
|
// the profile provided. A sharedConfig pointer type value is used so that
|
||||||
|
// multiple config file loadings can be chained.
|
||||||
|
//
|
||||||
|
// Only loads complete logically grouped values, and will not set fields in cfg
|
||||||
|
// for incomplete grouped values in the config. Such as credentials. For example
|
||||||
|
// if a config file only includes aws_access_key_id but no aws_secret_access_key
|
||||||
|
// the aws_access_key_id will be ignored.
|
||||||
|
func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile) error {
|
||||||
|
section, err := file.IniData.GetSection(profile)
|
||||||
|
if err != nil {
|
||||||
|
// Fallback to to alternate profile name: profile <name>
|
||||||
|
section, err = file.IniData.GetSection(fmt.Sprintf("profile %s", profile))
|
||||||
|
if err != nil {
|
||||||
|
return SharedConfigProfileNotExistsError{Profile: profile, Err: err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shared Credentials
|
||||||
|
akid := section.Key(accessKeyIDKey).String()
|
||||||
|
secret := section.Key(secretAccessKey).String()
|
||||||
|
if len(akid) > 0 && len(secret) > 0 {
|
||||||
|
cfg.Creds = credentials.Value{
|
||||||
|
AccessKeyID: akid,
|
||||||
|
SecretAccessKey: secret,
|
||||||
|
SessionToken: section.Key(sessionTokenKey).String(),
|
||||||
|
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", file.Filename),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume Role
|
||||||
|
roleArn := section.Key(roleArnKey).String()
|
||||||
|
srcProfile := section.Key(sourceProfileKey).String()
|
||||||
|
if len(roleArn) > 0 && len(srcProfile) > 0 {
|
||||||
|
cfg.AssumeRole = assumeRoleConfig{
|
||||||
|
RoleARN: roleArn,
|
||||||
|
SourceProfile: srcProfile,
|
||||||
|
ExternalID: section.Key(externalIDKey).String(),
|
||||||
|
MFASerial: section.Key(mfaSerialKey).String(),
|
||||||
|
RoleSessionName: section.Key(roleSessionNameKey).String(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Region
|
||||||
|
if v := section.Key(regionKey).String(); len(v) > 0 {
|
||||||
|
cfg.Region = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SharedConfigLoadError is an error for the shared config file failed to load.
|
||||||
|
type SharedConfigLoadError struct {
|
||||||
|
Filename string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code is the short id of the error.
|
||||||
|
func (e SharedConfigLoadError) Code() string {
|
||||||
|
return "SharedConfigLoadError"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message is the description of the error
|
||||||
|
func (e SharedConfigLoadError) Message() string {
|
||||||
|
return fmt.Sprintf("failed to load config file, %s", e.Filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrigErr is the underlying error that caused the failure.
|
||||||
|
func (e SharedConfigLoadError) OrigErr() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error satisfies the error interface.
|
||||||
|
func (e SharedConfigLoadError) Error() string {
|
||||||
|
return awserr.SprintError(e.Code(), e.Message(), "", e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SharedConfigProfileNotExistsError is an error for the shared config when
|
||||||
|
// the profile was not find in the config file.
|
||||||
|
type SharedConfigProfileNotExistsError struct {
|
||||||
|
Profile string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code is the short id of the error.
|
||||||
|
func (e SharedConfigProfileNotExistsError) Code() string {
|
||||||
|
return "SharedConfigProfileNotExistsError"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message is the description of the error
|
||||||
|
func (e SharedConfigProfileNotExistsError) Message() string {
|
||||||
|
return fmt.Sprintf("failed to get profile, %s", e.Profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrigErr is the underlying error that caused the failure.
|
||||||
|
func (e SharedConfigProfileNotExistsError) OrigErr() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error satisfies the error interface.
|
||||||
|
func (e SharedConfigProfileNotExistsError) Error() string {
|
||||||
|
return awserr.SprintError(e.Code(), e.Message(), "", e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SharedConfigAssumeRoleError is an error for the shared config when the
|
||||||
|
// profile contains assume role information, but that information is invalid
|
||||||
|
// or not complete.
|
||||||
|
type SharedConfigAssumeRoleError struct {
|
||||||
|
RoleARN string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code is the short id of the error.
|
||||||
|
func (e SharedConfigAssumeRoleError) Code() string {
|
||||||
|
return "SharedConfigAssumeRoleError"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message is the description of the error
|
||||||
|
func (e SharedConfigAssumeRoleError) Message() string {
|
||||||
|
return fmt.Sprintf("failed to load assume role for %s, source profile has no shared credentials",
|
||||||
|
e.RoleARN)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrigErr is the underlying error that caused the failure.
|
||||||
|
func (e SharedConfigAssumeRoleError) OrigErr() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error satisfies the error interface.
|
||||||
|
func (e SharedConfigAssumeRoleError) Error() string {
|
||||||
|
return awserr.SprintError(e.Code(), e.Message(), "", nil)
|
||||||
|
}
|
82
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go
generated
vendored
Normal file
82
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package v4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// validator houses a set of rule needed for validation of a
|
||||||
|
// string value
|
||||||
|
type rules []rule
|
||||||
|
|
||||||
|
// rule interface allows for more flexible rules and just simply
|
||||||
|
// checks whether or not a value adheres to that rule
|
||||||
|
type rule interface {
|
||||||
|
IsValid(value string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid will iterate through all rules and see if any rules
|
||||||
|
// apply to the value and supports nested rules
|
||||||
|
func (r rules) IsValid(value string) bool {
|
||||||
|
for _, rule := range r {
|
||||||
|
if rule.IsValid(value) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// mapRule generic rule for maps
|
||||||
|
type mapRule map[string]struct{}
|
||||||
|
|
||||||
|
// IsValid for the map rule satisfies whether it exists in the map
|
||||||
|
func (m mapRule) IsValid(value string) bool {
|
||||||
|
_, ok := m[value]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// whitelist is a generic rule for whitelisting
|
||||||
|
type whitelist struct {
|
||||||
|
rule
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid for whitelist checks if the value is within the whitelist
|
||||||
|
func (w whitelist) IsValid(value string) bool {
|
||||||
|
return w.rule.IsValid(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// blacklist is a generic rule for blacklisting
|
||||||
|
type blacklist struct {
|
||||||
|
rule
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid for whitelist checks if the value is within the whitelist
|
||||||
|
func (b blacklist) IsValid(value string) bool {
|
||||||
|
return !b.rule.IsValid(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
type patterns []string
|
||||||
|
|
||||||
|
// IsValid for patterns checks each pattern and returns if a match has
|
||||||
|
// been found
|
||||||
|
func (p patterns) IsValid(value string) bool {
|
||||||
|
for _, pattern := range p {
|
||||||
|
if strings.HasPrefix(http.CanonicalHeaderKey(value), pattern) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// inclusiveRules rules allow for rules to depend on one another
|
||||||
|
type inclusiveRules []rule
|
||||||
|
|
||||||
|
// IsValid will return true if all rules are true
|
||||||
|
func (r inclusiveRules) IsValid(value string) bool {
|
||||||
|
for _, rule := range r {
|
||||||
|
if !rule.IsValid(value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
24
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/uri_path.go
generated
vendored
Normal file
24
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/uri_path.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
|
package v4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getURIPath(u *url.URL) string {
|
||||||
|
var uri string
|
||||||
|
|
||||||
|
if len(u.Opaque) > 0 {
|
||||||
|
uri = "/" + strings.Join(strings.Split(u.Opaque, "/")[3:], "/")
|
||||||
|
} else {
|
||||||
|
uri = u.EscapedPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(uri) == 0 {
|
||||||
|
uri = "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri
|
||||||
|
}
|
740
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go
generated
vendored
Normal file
740
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go
generated
vendored
Normal file
|
@ -0,0 +1,740 @@
|
||||||
|
// Package v4 implements signing for AWS V4 signer
|
||||||
|
//
|
||||||
|
// Provides request signing for request that need to be signed with
|
||||||
|
// AWS V4 Signatures.
|
||||||
|
//
|
||||||
|
// Standalone Signer
|
||||||
|
//
|
||||||
|
// Generally using the signer outside of the SDK should not require any additional
|
||||||
|
// logic when using Go v1.5 or higher. The signer does this by taking advantage
|
||||||
|
// of the URL.EscapedPath method. If your request URI requires additional escaping
|
||||||
|
// you many need to use the URL.Opaque to define what the raw URI should be sent
|
||||||
|
// to the service as.
|
||||||
|
//
|
||||||
|
// The signer will first check the URL.Opaque field, and use its value if set.
|
||||||
|
// The signer does require the URL.Opaque field to be set in the form of:
|
||||||
|
//
|
||||||
|
// "//<hostname>/<path>"
|
||||||
|
//
|
||||||
|
// // e.g.
|
||||||
|
// "//example.com/some/path"
|
||||||
|
//
|
||||||
|
// The leading "//" and hostname are required or the URL.Opaque escaping will
|
||||||
|
// not work correctly.
|
||||||
|
//
|
||||||
|
// If URL.Opaque is not set the signer will fallback to the URL.EscapedPath()
|
||||||
|
// method and using the returned value. If you're using Go v1.4 you must set
|
||||||
|
// URL.Opaque if the URI path needs escaping. If URL.Opaque is not set with
|
||||||
|
// Go v1.5 the signer will fallback to URL.Path.
|
||||||
|
//
|
||||||
|
// AWS v4 signature validation requires that the canonical string's URI path
|
||||||
|
// element must be the URI escaped form of the HTTP request's path.
|
||||||
|
// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||||
|
//
|
||||||
|
// The Go HTTP client will perform escaping automatically on the request. Some
|
||||||
|
// of these escaping may cause signature validation errors because the HTTP
|
||||||
|
// request differs from the URI path or query that the signature was generated.
|
||||||
|
// https://golang.org/pkg/net/url/#URL.EscapedPath
|
||||||
|
//
|
||||||
|
// Because of this, it is recommended that when using the signer outside of the
|
||||||
|
// SDK that explicitly escaping the request prior to being signed is preferable,
|
||||||
|
// and will help prevent signature validation errors. This can be done by setting
|
||||||
|
// the URL.Opaque or URL.RawPath. The SDK will use URL.Opaque first and then
|
||||||
|
// call URL.EscapedPath() if Opaque is not set.
|
||||||
|
//
|
||||||
|
// If signing a request intended for HTTP2 server, and you're using Go 1.6.2
|
||||||
|
// through 1.7.4 you should use the URL.RawPath as the pre-escaped form of the
|
||||||
|
// request URL. https://github.com/golang/go/issues/16847 points to a bug in
|
||||||
|
// Go pre 1.8 that failes to make HTTP2 requests using absolute URL in the HTTP
|
||||||
|
// message. URL.Opaque generally will force Go to make requests with absolute URL.
|
||||||
|
// URL.RawPath does not do this, but RawPath must be a valid escaping of Path
|
||||||
|
// or url.EscapedPath will ignore the RawPath escaping.
|
||||||
|
//
|
||||||
|
// Test `TestStandaloneSign` provides a complete example of using the signer
|
||||||
|
// outside of the SDK and pre-escaping the URI path.
|
||||||
|
package v4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol/rest"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
authHeaderPrefix = "AWS4-HMAC-SHA256"
|
||||||
|
timeFormat = "20060102T150405Z"
|
||||||
|
shortTimeFormat = "20060102"
|
||||||
|
|
||||||
|
// emptyStringSHA256 is a SHA256 of an empty string
|
||||||
|
emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
|
||||||
|
)
|
||||||
|
|
||||||
|
var ignoredHeaders = rules{
|
||||||
|
blacklist{
|
||||||
|
mapRule{
|
||||||
|
"Authorization": struct{}{},
|
||||||
|
"User-Agent": struct{}{},
|
||||||
|
"X-Amzn-Trace-Id": struct{}{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// requiredSignedHeaders is a whitelist for build canonical headers.
|
||||||
|
var requiredSignedHeaders = rules{
|
||||||
|
whitelist{
|
||||||
|
mapRule{
|
||||||
|
"Cache-Control": struct{}{},
|
||||||
|
"Content-Disposition": struct{}{},
|
||||||
|
"Content-Encoding": struct{}{},
|
||||||
|
"Content-Language": struct{}{},
|
||||||
|
"Content-Md5": struct{}{},
|
||||||
|
"Content-Type": struct{}{},
|
||||||
|
"Expires": struct{}{},
|
||||||
|
"If-Match": struct{}{},
|
||||||
|
"If-Modified-Since": struct{}{},
|
||||||
|
"If-None-Match": struct{}{},
|
||||||
|
"If-Unmodified-Since": struct{}{},
|
||||||
|
"Range": struct{}{},
|
||||||
|
"X-Amz-Acl": struct{}{},
|
||||||
|
"X-Amz-Copy-Source": struct{}{},
|
||||||
|
"X-Amz-Copy-Source-If-Match": struct{}{},
|
||||||
|
"X-Amz-Copy-Source-If-Modified-Since": struct{}{},
|
||||||
|
"X-Amz-Copy-Source-If-None-Match": struct{}{},
|
||||||
|
"X-Amz-Copy-Source-If-Unmodified-Since": struct{}{},
|
||||||
|
"X-Amz-Copy-Source-Range": struct{}{},
|
||||||
|
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm": struct{}{},
|
||||||
|
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key": struct{}{},
|
||||||
|
"X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
|
||||||
|
"X-Amz-Grant-Full-control": struct{}{},
|
||||||
|
"X-Amz-Grant-Read": struct{}{},
|
||||||
|
"X-Amz-Grant-Read-Acp": struct{}{},
|
||||||
|
"X-Amz-Grant-Write": struct{}{},
|
||||||
|
"X-Amz-Grant-Write-Acp": struct{}{},
|
||||||
|
"X-Amz-Metadata-Directive": struct{}{},
|
||||||
|
"X-Amz-Mfa": struct{}{},
|
||||||
|
"X-Amz-Request-Payer": struct{}{},
|
||||||
|
"X-Amz-Server-Side-Encryption": struct{}{},
|
||||||
|
"X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": struct{}{},
|
||||||
|
"X-Amz-Server-Side-Encryption-Customer-Algorithm": struct{}{},
|
||||||
|
"X-Amz-Server-Side-Encryption-Customer-Key": struct{}{},
|
||||||
|
"X-Amz-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
|
||||||
|
"X-Amz-Storage-Class": struct{}{},
|
||||||
|
"X-Amz-Website-Redirect-Location": struct{}{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
patterns{"X-Amz-Meta-"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// allowedHoisting is a whitelist for build query headers. The boolean value
|
||||||
|
// represents whether or not it is a pattern.
|
||||||
|
var allowedQueryHoisting = inclusiveRules{
|
||||||
|
blacklist{requiredSignedHeaders},
|
||||||
|
patterns{"X-Amz-"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signer applies AWS v4 signing to given request. Use this to sign requests
|
||||||
|
// that need to be signed with AWS V4 Signatures.
|
||||||
|
type Signer struct {
|
||||||
|
// The authentication credentials the request will be signed against.
|
||||||
|
// This value must be set to sign requests.
|
||||||
|
Credentials *credentials.Credentials
|
||||||
|
|
||||||
|
// Sets the log level the signer should use when reporting information to
|
||||||
|
// the logger. If the logger is nil nothing will be logged. See
|
||||||
|
// aws.LogLevelType for more information on available logging levels
|
||||||
|
//
|
||||||
|
// By default nothing will be logged.
|
||||||
|
Debug aws.LogLevelType
|
||||||
|
|
||||||
|
// The logger loging information will be written to. If there the logger
|
||||||
|
// is nil, nothing will be logged.
|
||||||
|
Logger aws.Logger
|
||||||
|
|
||||||
|
// Disables the Signer's moving HTTP header key/value pairs from the HTTP
|
||||||
|
// request header to the request's query string. This is most commonly used
|
||||||
|
// with pre-signed requests preventing headers from being added to the
|
||||||
|
// request's query string.
|
||||||
|
DisableHeaderHoisting bool
|
||||||
|
|
||||||
|
// Disables the automatic escaping of the URI path of the request for the
|
||||||
|
// siganture's canonical string's path. For services that do not need additional
|
||||||
|
// escaping then use this to disable the signer escaping the path.
|
||||||
|
//
|
||||||
|
// S3 is an example of a service that does not need additional escaping.
|
||||||
|
//
|
||||||
|
// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||||
|
DisableURIPathEscaping bool
|
||||||
|
|
||||||
|
// Disales the automatical setting of the HTTP request's Body field with the
|
||||||
|
// io.ReadSeeker passed in to the signer. This is useful if you're using a
|
||||||
|
// custom wrapper around the body for the io.ReadSeeker and want to preserve
|
||||||
|
// the Body value on the Request.Body.
|
||||||
|
//
|
||||||
|
// This does run the risk of signing a request with a body that will not be
|
||||||
|
// sent in the request. Need to ensure that the underlying data of the Body
|
||||||
|
// values are the same.
|
||||||
|
DisableRequestBodyOverwrite bool
|
||||||
|
|
||||||
|
// currentTimeFn returns the time value which represents the current time.
|
||||||
|
// This value should only be used for testing. If it is nil the default
|
||||||
|
// time.Now will be used.
|
||||||
|
currentTimeFn func() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSigner returns a Signer pointer configured with the credentials and optional
|
||||||
|
// option values provided. If not options are provided the Signer will use its
|
||||||
|
// default configuration.
|
||||||
|
func NewSigner(credentials *credentials.Credentials, options ...func(*Signer)) *Signer {
|
||||||
|
v4 := &Signer{
|
||||||
|
Credentials: credentials,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(v4)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v4
|
||||||
|
}
|
||||||
|
|
||||||
|
type signingCtx struct {
|
||||||
|
ServiceName string
|
||||||
|
Region string
|
||||||
|
Request *http.Request
|
||||||
|
Body io.ReadSeeker
|
||||||
|
Query url.Values
|
||||||
|
Time time.Time
|
||||||
|
ExpireTime time.Duration
|
||||||
|
SignedHeaderVals http.Header
|
||||||
|
|
||||||
|
DisableURIPathEscaping bool
|
||||||
|
|
||||||
|
credValues credentials.Value
|
||||||
|
isPresign bool
|
||||||
|
formattedTime string
|
||||||
|
formattedShortTime string
|
||||||
|
|
||||||
|
bodyDigest string
|
||||||
|
signedHeaders string
|
||||||
|
canonicalHeaders string
|
||||||
|
canonicalString string
|
||||||
|
credentialString string
|
||||||
|
stringToSign string
|
||||||
|
signature string
|
||||||
|
authorization string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign signs AWS v4 requests with the provided body, service name, region the
|
||||||
|
// request is made to, and time the request is signed at. The signTime allows
|
||||||
|
// you to specify that a request is signed for the future, and cannot be
|
||||||
|
// used until then.
|
||||||
|
//
|
||||||
|
// Returns a list of HTTP headers that were included in the signature or an
|
||||||
|
// error if signing the request failed. Generally for signed requests this value
|
||||||
|
// is not needed as the full request context will be captured by the http.Request
|
||||||
|
// value. It is included for reference though.
|
||||||
|
//
|
||||||
|
// Sign will set the request's Body to be the `body` parameter passed in. If
|
||||||
|
// the body is not already an io.ReadCloser, it will be wrapped within one. If
|
||||||
|
// a `nil` body parameter passed to Sign, the request's Body field will be
|
||||||
|
// also set to nil. Its important to note that this functionality will not
|
||||||
|
// change the request's ContentLength of the request.
|
||||||
|
//
|
||||||
|
// Sign differs from Presign in that it will sign the request using HTTP
|
||||||
|
// header values. This type of signing is intended for http.Request values that
|
||||||
|
// will not be shared, or are shared in a way the header values on the request
|
||||||
|
// will not be lost.
|
||||||
|
//
|
||||||
|
// The requests body is an io.ReadSeeker so the SHA256 of the body can be
|
||||||
|
// generated. To bypass the signer computing the hash you can set the
|
||||||
|
// "X-Amz-Content-Sha256" header with a precomputed value. The signer will
|
||||||
|
// only compute the hash if the request header value is empty.
|
||||||
|
func (v4 Signer) Sign(r *http.Request, body io.ReadSeeker, service, region string, signTime time.Time) (http.Header, error) {
|
||||||
|
return v4.signWithBody(r, body, service, region, 0, signTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Presign signs AWS v4 requests with the provided body, service name, region
|
||||||
|
// the request is made to, and time the request is signed at. The signTime
|
||||||
|
// allows you to specify that a request is signed for the future, and cannot
|
||||||
|
// be used until then.
|
||||||
|
//
|
||||||
|
// Returns a list of HTTP headers that were included in the signature or an
|
||||||
|
// error if signing the request failed. For presigned requests these headers
|
||||||
|
// and their values must be included on the HTTP request when it is made. This
|
||||||
|
// is helpful to know what header values need to be shared with the party the
|
||||||
|
// presigned request will be distributed to.
|
||||||
|
//
|
||||||
|
// Presign differs from Sign in that it will sign the request using query string
|
||||||
|
// instead of header values. This allows you to share the Presigned Request's
|
||||||
|
// URL with third parties, or distribute it throughout your system with minimal
|
||||||
|
// dependencies.
|
||||||
|
//
|
||||||
|
// Presign also takes an exp value which is the duration the
|
||||||
|
// signed request will be valid after the signing time. This is allows you to
|
||||||
|
// set when the request will expire.
|
||||||
|
//
|
||||||
|
// The requests body is an io.ReadSeeker so the SHA256 of the body can be
|
||||||
|
// generated. To bypass the signer computing the hash you can set the
|
||||||
|
// "X-Amz-Content-Sha256" header with a precomputed value. The signer will
|
||||||
|
// only compute the hash if the request header value is empty.
|
||||||
|
//
|
||||||
|
// Presigning a S3 request will not compute the body's SHA256 hash by default.
|
||||||
|
// This is done due to the general use case for S3 presigned URLs is to share
|
||||||
|
// PUT/GET capabilities. If you would like to include the body's SHA256 in the
|
||||||
|
// presigned request's signature you can set the "X-Amz-Content-Sha256"
|
||||||
|
// HTTP header and that will be included in the request's signature.
|
||||||
|
func (v4 Signer) Presign(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) {
|
||||||
|
return v4.signWithBody(r, body, service, region, exp, signTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) {
|
||||||
|
currentTimeFn := v4.currentTimeFn
|
||||||
|
if currentTimeFn == nil {
|
||||||
|
currentTimeFn = time.Now
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := &signingCtx{
|
||||||
|
Request: r,
|
||||||
|
Body: body,
|
||||||
|
Query: r.URL.Query(),
|
||||||
|
Time: signTime,
|
||||||
|
ExpireTime: exp,
|
||||||
|
isPresign: exp != 0,
|
||||||
|
ServiceName: service,
|
||||||
|
Region: region,
|
||||||
|
DisableURIPathEscaping: v4.DisableURIPathEscaping,
|
||||||
|
}
|
||||||
|
|
||||||
|
for key := range ctx.Query {
|
||||||
|
sort.Strings(ctx.Query[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.isRequestSigned() {
|
||||||
|
ctx.Time = currentTimeFn()
|
||||||
|
ctx.handlePresignRemoval()
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
ctx.credValues, err = v4.Credentials.Get()
|
||||||
|
if err != nil {
|
||||||
|
return http.Header{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.assignAmzQueryValues()
|
||||||
|
ctx.build(v4.DisableHeaderHoisting)
|
||||||
|
|
||||||
|
// If the request is not presigned the body should be attached to it. This
|
||||||
|
// prevents the confusion of wanting to send a signed request without
|
||||||
|
// the body the request was signed for attached.
|
||||||
|
if !(v4.DisableRequestBodyOverwrite || ctx.isPresign) {
|
||||||
|
var reader io.ReadCloser
|
||||||
|
if body != nil {
|
||||||
|
var ok bool
|
||||||
|
if reader, ok = body.(io.ReadCloser); !ok {
|
||||||
|
reader = ioutil.NopCloser(body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.Body = reader
|
||||||
|
}
|
||||||
|
|
||||||
|
if v4.Debug.Matches(aws.LogDebugWithSigning) {
|
||||||
|
v4.logSigningInfo(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.SignedHeaderVals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *signingCtx) handlePresignRemoval() {
|
||||||
|
if !ctx.isPresign {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The credentials have expired for this request. The current signing
|
||||||
|
// is invalid, and needs to be request because the request will fail.
|
||||||
|
ctx.removePresign()
|
||||||
|
|
||||||
|
// Update the request's query string to ensure the values stays in
|
||||||
|
// sync in the case retrieving the new credentials fails.
|
||||||
|
ctx.Request.URL.RawQuery = ctx.Query.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *signingCtx) assignAmzQueryValues() {
|
||||||
|
if ctx.isPresign {
|
||||||
|
ctx.Query.Set("X-Amz-Algorithm", authHeaderPrefix)
|
||||||
|
if ctx.credValues.SessionToken != "" {
|
||||||
|
ctx.Query.Set("X-Amz-Security-Token", ctx.credValues.SessionToken)
|
||||||
|
} else {
|
||||||
|
ctx.Query.Del("X-Amz-Security-Token")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.credValues.SessionToken != "" {
|
||||||
|
ctx.Request.Header.Set("X-Amz-Security-Token", ctx.credValues.SessionToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignRequestHandler is a named request handler the SDK will use to sign
|
||||||
|
// service client request with using the V4 signature.
|
||||||
|
var SignRequestHandler = request.NamedHandler{
|
||||||
|
Name: "v4.SignRequestHandler", Fn: SignSDKRequest,
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignSDKRequest signs an AWS request with the V4 signature. This
|
||||||
|
// request handler is bested used only with the SDK's built in service client's
|
||||||
|
// API operation requests.
|
||||||
|
//
|
||||||
|
// This function should not be used on its on its own, but in conjunction with
|
||||||
|
// an AWS service client's API operation call. To sign a standalone request
|
||||||
|
// not created by a service client's API operation method use the "Sign" or
|
||||||
|
// "Presign" functions of the "Signer" type.
|
||||||
|
//
|
||||||
|
// If the credentials of the request's config are set to
|
||||||
|
// credentials.AnonymousCredentials the request will not be signed.
|
||||||
|
func SignSDKRequest(req *request.Request) {
|
||||||
|
signSDKRequestWithCurrTime(req, time.Now)
|
||||||
|
}
|
||||||
|
func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time) {
|
||||||
|
// If the request does not need to be signed ignore the signing of the
|
||||||
|
// request if the AnonymousCredentials object is used.
|
||||||
|
if req.Config.Credentials == credentials.AnonymousCredentials {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
region := req.ClientInfo.SigningRegion
|
||||||
|
if region == "" {
|
||||||
|
region = aws.StringValue(req.Config.Region)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := req.ClientInfo.SigningName
|
||||||
|
if name == "" {
|
||||||
|
name = req.ClientInfo.ServiceName
|
||||||
|
}
|
||||||
|
|
||||||
|
v4 := NewSigner(req.Config.Credentials, func(v4 *Signer) {
|
||||||
|
v4.Debug = req.Config.LogLevel.Value()
|
||||||
|
v4.Logger = req.Config.Logger
|
||||||
|
v4.DisableHeaderHoisting = req.NotHoist
|
||||||
|
v4.currentTimeFn = curTimeFn
|
||||||
|
if name == "s3" {
|
||||||
|
// S3 service should not have any escaping applied
|
||||||
|
v4.DisableURIPathEscaping = true
|
||||||
|
}
|
||||||
|
// Prevents setting the HTTPRequest's Body. Since the Body could be
|
||||||
|
// wrapped in a custom io.Closer that we do not want to be stompped
|
||||||
|
// on top of by the signer.
|
||||||
|
v4.DisableRequestBodyOverwrite = true
|
||||||
|
})
|
||||||
|
|
||||||
|
signingTime := req.Time
|
||||||
|
if !req.LastSignedAt.IsZero() {
|
||||||
|
signingTime = req.LastSignedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.GetBody(),
|
||||||
|
name, region, req.ExpireTime, signingTime,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
req.Error = err
|
||||||
|
req.SignedHeaderVals = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.SignedHeaderVals = signedHeaders
|
||||||
|
req.LastSignedAt = curTimeFn()
|
||||||
|
}
|
||||||
|
|
||||||
|
const logSignInfoMsg = `DEBUG: Request Signature:
|
||||||
|
---[ CANONICAL STRING ]-----------------------------
|
||||||
|
%s
|
||||||
|
---[ STRING TO SIGN ]--------------------------------
|
||||||
|
%s%s
|
||||||
|
-----------------------------------------------------`
|
||||||
|
const logSignedURLMsg = `
|
||||||
|
---[ SIGNED URL ]------------------------------------
|
||||||
|
%s`
|
||||||
|
|
||||||
|
func (v4 *Signer) logSigningInfo(ctx *signingCtx) {
|
||||||
|
signedURLMsg := ""
|
||||||
|
if ctx.isPresign {
|
||||||
|
signedURLMsg = fmt.Sprintf(logSignedURLMsg, ctx.Request.URL.String())
|
||||||
|
}
|
||||||
|
msg := fmt.Sprintf(logSignInfoMsg, ctx.canonicalString, ctx.stringToSign, signedURLMsg)
|
||||||
|
v4.Logger.Log(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *signingCtx) build(disableHeaderHoisting bool) {
|
||||||
|
ctx.buildTime() // no depends
|
||||||
|
ctx.buildCredentialString() // no depends
|
||||||
|
|
||||||
|
unsignedHeaders := ctx.Request.Header
|
||||||
|
if ctx.isPresign {
|
||||||
|
if !disableHeaderHoisting {
|
||||||
|
urlValues := url.Values{}
|
||||||
|
urlValues, unsignedHeaders = buildQuery(allowedQueryHoisting, unsignedHeaders) // no depends
|
||||||
|
for k := range urlValues {
|
||||||
|
ctx.Query[k] = urlValues[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.buildBodyDigest()
|
||||||
|
ctx.buildCanonicalHeaders(ignoredHeaders, unsignedHeaders)
|
||||||
|
ctx.buildCanonicalString() // depends on canon headers / signed headers
|
||||||
|
ctx.buildStringToSign() // depends on canon string
|
||||||
|
ctx.buildSignature() // depends on string to sign
|
||||||
|
|
||||||
|
if ctx.isPresign {
|
||||||
|
ctx.Request.URL.RawQuery += "&X-Amz-Signature=" + ctx.signature
|
||||||
|
} else {
|
||||||
|
parts := []string{
|
||||||
|
authHeaderPrefix + " Credential=" + ctx.credValues.AccessKeyID + "/" + ctx.credentialString,
|
||||||
|
"SignedHeaders=" + ctx.signedHeaders,
|
||||||
|
"Signature=" + ctx.signature,
|
||||||
|
}
|
||||||
|
ctx.Request.Header.Set("Authorization", strings.Join(parts, ", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *signingCtx) buildTime() {
|
||||||
|
ctx.formattedTime = ctx.Time.UTC().Format(timeFormat)
|
||||||
|
ctx.formattedShortTime = ctx.Time.UTC().Format(shortTimeFormat)
|
||||||
|
|
||||||
|
if ctx.isPresign {
|
||||||
|
duration := int64(ctx.ExpireTime / time.Second)
|
||||||
|
ctx.Query.Set("X-Amz-Date", ctx.formattedTime)
|
||||||
|
ctx.Query.Set("X-Amz-Expires", strconv.FormatInt(duration, 10))
|
||||||
|
} else {
|
||||||
|
ctx.Request.Header.Set("X-Amz-Date", ctx.formattedTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *signingCtx) buildCredentialString() {
|
||||||
|
ctx.credentialString = strings.Join([]string{
|
||||||
|
ctx.formattedShortTime,
|
||||||
|
ctx.Region,
|
||||||
|
ctx.ServiceName,
|
||||||
|
"aws4_request",
|
||||||
|
}, "/")
|
||||||
|
|
||||||
|
if ctx.isPresign {
|
||||||
|
ctx.Query.Set("X-Amz-Credential", ctx.credValues.AccessKeyID+"/"+ctx.credentialString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildQuery(r rule, header http.Header) (url.Values, http.Header) {
|
||||||
|
query := url.Values{}
|
||||||
|
unsignedHeaders := http.Header{}
|
||||||
|
for k, h := range header {
|
||||||
|
if r.IsValid(k) {
|
||||||
|
query[k] = h
|
||||||
|
} else {
|
||||||
|
unsignedHeaders[k] = h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return query, unsignedHeaders
|
||||||
|
}
|
||||||
|
func (ctx *signingCtx) buildCanonicalHeaders(r rule, header http.Header) {
|
||||||
|
var headers []string
|
||||||
|
headers = append(headers, "host")
|
||||||
|
for k, v := range header {
|
||||||
|
canonicalKey := http.CanonicalHeaderKey(k)
|
||||||
|
if !r.IsValid(canonicalKey) {
|
||||||
|
continue // ignored header
|
||||||
|
}
|
||||||
|
if ctx.SignedHeaderVals == nil {
|
||||||
|
ctx.SignedHeaderVals = make(http.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
lowerCaseKey := strings.ToLower(k)
|
||||||
|
if _, ok := ctx.SignedHeaderVals[lowerCaseKey]; ok {
|
||||||
|
// include additional values
|
||||||
|
ctx.SignedHeaderVals[lowerCaseKey] = append(ctx.SignedHeaderVals[lowerCaseKey], v...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = append(headers, lowerCaseKey)
|
||||||
|
ctx.SignedHeaderVals[lowerCaseKey] = v
|
||||||
|
}
|
||||||
|
sort.Strings(headers)
|
||||||
|
|
||||||
|
ctx.signedHeaders = strings.Join(headers, ";")
|
||||||
|
|
||||||
|
if ctx.isPresign {
|
||||||
|
ctx.Query.Set("X-Amz-SignedHeaders", ctx.signedHeaders)
|
||||||
|
}
|
||||||
|
|
||||||
|
headerValues := make([]string, len(headers))
|
||||||
|
for i, k := range headers {
|
||||||
|
if k == "host" {
|
||||||
|
headerValues[i] = "host:" + ctx.Request.URL.Host
|
||||||
|
} else {
|
||||||
|
headerValues[i] = k + ":" +
|
||||||
|
strings.Join(ctx.SignedHeaderVals[k], ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.canonicalHeaders = strings.Join(stripExcessSpaces(headerValues), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *signingCtx) buildCanonicalString() {
|
||||||
|
ctx.Request.URL.RawQuery = strings.Replace(ctx.Query.Encode(), "+", "%20", -1)
|
||||||
|
|
||||||
|
uri := getURIPath(ctx.Request.URL)
|
||||||
|
|
||||||
|
if !ctx.DisableURIPathEscaping {
|
||||||
|
uri = rest.EscapePath(uri, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.canonicalString = strings.Join([]string{
|
||||||
|
ctx.Request.Method,
|
||||||
|
uri,
|
||||||
|
ctx.Request.URL.RawQuery,
|
||||||
|
ctx.canonicalHeaders + "\n",
|
||||||
|
ctx.signedHeaders,
|
||||||
|
ctx.bodyDigest,
|
||||||
|
}, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *signingCtx) buildStringToSign() {
|
||||||
|
ctx.stringToSign = strings.Join([]string{
|
||||||
|
authHeaderPrefix,
|
||||||
|
ctx.formattedTime,
|
||||||
|
ctx.credentialString,
|
||||||
|
hex.EncodeToString(makeSha256([]byte(ctx.canonicalString))),
|
||||||
|
}, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *signingCtx) buildSignature() {
|
||||||
|
secret := ctx.credValues.SecretAccessKey
|
||||||
|
date := makeHmac([]byte("AWS4"+secret), []byte(ctx.formattedShortTime))
|
||||||
|
region := makeHmac(date, []byte(ctx.Region))
|
||||||
|
service := makeHmac(region, []byte(ctx.ServiceName))
|
||||||
|
credentials := makeHmac(service, []byte("aws4_request"))
|
||||||
|
signature := makeHmac(credentials, []byte(ctx.stringToSign))
|
||||||
|
ctx.signature = hex.EncodeToString(signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *signingCtx) buildBodyDigest() {
|
||||||
|
hash := ctx.Request.Header.Get("X-Amz-Content-Sha256")
|
||||||
|
if hash == "" {
|
||||||
|
if ctx.isPresign && ctx.ServiceName == "s3" {
|
||||||
|
hash = "UNSIGNED-PAYLOAD"
|
||||||
|
} else if ctx.Body == nil {
|
||||||
|
hash = emptyStringSHA256
|
||||||
|
} else {
|
||||||
|
hash = hex.EncodeToString(makeSha256Reader(ctx.Body))
|
||||||
|
}
|
||||||
|
if ctx.ServiceName == "s3" || ctx.ServiceName == "glacier" {
|
||||||
|
ctx.Request.Header.Set("X-Amz-Content-Sha256", hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.bodyDigest = hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// isRequestSigned returns if the request is currently signed or presigned
|
||||||
|
func (ctx *signingCtx) isRequestSigned() bool {
|
||||||
|
if ctx.isPresign && ctx.Query.Get("X-Amz-Signature") != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if ctx.Request.Header.Get("Authorization") != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsign removes signing flags for both signed and presigned requests.
|
||||||
|
func (ctx *signingCtx) removePresign() {
|
||||||
|
ctx.Query.Del("X-Amz-Algorithm")
|
||||||
|
ctx.Query.Del("X-Amz-Signature")
|
||||||
|
ctx.Query.Del("X-Amz-Security-Token")
|
||||||
|
ctx.Query.Del("X-Amz-Date")
|
||||||
|
ctx.Query.Del("X-Amz-Expires")
|
||||||
|
ctx.Query.Del("X-Amz-Credential")
|
||||||
|
ctx.Query.Del("X-Amz-SignedHeaders")
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeHmac(key []byte, data []byte) []byte {
|
||||||
|
hash := hmac.New(sha256.New, key)
|
||||||
|
hash.Write(data)
|
||||||
|
return hash.Sum(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSha256(data []byte) []byte {
|
||||||
|
hash := sha256.New()
|
||||||
|
hash.Write(data)
|
||||||
|
return hash.Sum(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSha256Reader(reader io.ReadSeeker) []byte {
|
||||||
|
hash := sha256.New()
|
||||||
|
start, _ := reader.Seek(0, 1)
|
||||||
|
defer reader.Seek(start, 0)
|
||||||
|
|
||||||
|
io.Copy(hash, reader)
|
||||||
|
return hash.Sum(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
const doubleSpaces = " "
|
||||||
|
|
||||||
|
var doubleSpaceBytes = []byte(doubleSpaces)
|
||||||
|
|
||||||
|
func stripExcessSpaces(headerVals []string) []string {
|
||||||
|
vals := make([]string, len(headerVals))
|
||||||
|
for i, str := range headerVals {
|
||||||
|
// Trim leading and trailing spaces
|
||||||
|
trimmed := strings.TrimSpace(str)
|
||||||
|
|
||||||
|
idx := strings.Index(trimmed, doubleSpaces)
|
||||||
|
var buf []byte
|
||||||
|
for idx > -1 {
|
||||||
|
// Multiple adjacent spaces found
|
||||||
|
if buf == nil {
|
||||||
|
// first time create the buffer
|
||||||
|
buf = []byte(trimmed)
|
||||||
|
}
|
||||||
|
|
||||||
|
stripToIdx := -1
|
||||||
|
for j := idx + 1; j < len(buf); j++ {
|
||||||
|
if buf[j] != ' ' {
|
||||||
|
buf = append(buf[:idx+1], buf[j:]...)
|
||||||
|
stripToIdx = j
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if stripToIdx >= 0 {
|
||||||
|
idx = bytes.Index(buf[stripToIdx:], doubleSpaceBytes)
|
||||||
|
if idx >= 0 {
|
||||||
|
idx += stripToIdx
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
idx = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if buf != nil {
|
||||||
|
vals[i] = string(buf)
|
||||||
|
} else {
|
||||||
|
vals[i] = trimmed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vals
|
||||||
|
}
|
118
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/types.go
generated
vendored
Normal file
118
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/types.go
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser. Should
|
||||||
|
// only be used with an io.Reader that is also an io.Seeker. Doing so may
|
||||||
|
// cause request signature errors, or request body's not sent for GET, HEAD
|
||||||
|
// and DELETE HTTP methods.
|
||||||
|
//
|
||||||
|
// Deprecated: Should only be used with io.ReadSeeker. If using for
|
||||||
|
// S3 PutObject to stream content use s3manager.Uploader instead.
|
||||||
|
func ReadSeekCloser(r io.Reader) ReaderSeekerCloser {
|
||||||
|
return ReaderSeekerCloser{r}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReaderSeekerCloser represents a reader that can also delegate io.Seeker and
|
||||||
|
// io.Closer interfaces to the underlying object if they are available.
|
||||||
|
type ReaderSeekerCloser struct {
|
||||||
|
r io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads from the reader up to size of p. The number of bytes read, and
|
||||||
|
// error if it occurred will be returned.
|
||||||
|
//
|
||||||
|
// If the reader is not an io.Reader zero bytes read, and nil error will be returned.
|
||||||
|
//
|
||||||
|
// Performs the same functionality as io.Reader Read
|
||||||
|
func (r ReaderSeekerCloser) Read(p []byte) (int, error) {
|
||||||
|
switch t := r.r.(type) {
|
||||||
|
case io.Reader:
|
||||||
|
return t.Read(p)
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek sets the offset for the next Read to offset, interpreted according to
|
||||||
|
// whence: 0 means relative to the origin of the file, 1 means relative to the
|
||||||
|
// current offset, and 2 means relative to the end. Seek returns the new offset
|
||||||
|
// and an error, if any.
|
||||||
|
//
|
||||||
|
// If the ReaderSeekerCloser is not an io.Seeker nothing will be done.
|
||||||
|
func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) {
|
||||||
|
switch t := r.r.(type) {
|
||||||
|
case io.Seeker:
|
||||||
|
return t.Seek(offset, whence)
|
||||||
|
}
|
||||||
|
return int64(0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSeeker returns if the underlying reader is also a seeker.
|
||||||
|
func (r ReaderSeekerCloser) IsSeeker() bool {
|
||||||
|
_, ok := r.r.(io.Seeker)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the ReaderSeekerCloser.
|
||||||
|
//
|
||||||
|
// If the ReaderSeekerCloser is not an io.Closer nothing will be done.
|
||||||
|
func (r ReaderSeekerCloser) Close() error {
|
||||||
|
switch t := r.r.(type) {
|
||||||
|
case io.Closer:
|
||||||
|
return t.Close()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A WriteAtBuffer provides a in memory buffer supporting the io.WriterAt interface
|
||||||
|
// Can be used with the s3manager.Downloader to download content to a buffer
|
||||||
|
// in memory. Safe to use concurrently.
|
||||||
|
type WriteAtBuffer struct {
|
||||||
|
buf []byte
|
||||||
|
m sync.Mutex
|
||||||
|
|
||||||
|
// GrowthCoeff defines the growth rate of the internal buffer. By
|
||||||
|
// default, the growth rate is 1, where expanding the internal
|
||||||
|
// buffer will allocate only enough capacity to fit the new expected
|
||||||
|
// length.
|
||||||
|
GrowthCoeff float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWriteAtBuffer creates a WriteAtBuffer with an internal buffer
|
||||||
|
// provided by buf.
|
||||||
|
func NewWriteAtBuffer(buf []byte) *WriteAtBuffer {
|
||||||
|
return &WriteAtBuffer{buf: buf}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteAt writes a slice of bytes to a buffer starting at the position provided
|
||||||
|
// The number of bytes written will be returned, or error. Can overwrite previous
|
||||||
|
// written slices if the write ats overlap.
|
||||||
|
func (b *WriteAtBuffer) WriteAt(p []byte, pos int64) (n int, err error) {
|
||||||
|
pLen := len(p)
|
||||||
|
expLen := pos + int64(pLen)
|
||||||
|
b.m.Lock()
|
||||||
|
defer b.m.Unlock()
|
||||||
|
if int64(len(b.buf)) < expLen {
|
||||||
|
if int64(cap(b.buf)) < expLen {
|
||||||
|
if b.GrowthCoeff < 1 {
|
||||||
|
b.GrowthCoeff = 1
|
||||||
|
}
|
||||||
|
newBuf := make([]byte, expLen, int64(b.GrowthCoeff*float64(expLen)))
|
||||||
|
copy(newBuf, b.buf)
|
||||||
|
b.buf = newBuf
|
||||||
|
}
|
||||||
|
b.buf = b.buf[:expLen]
|
||||||
|
}
|
||||||
|
copy(b.buf[pos:], p)
|
||||||
|
return pLen, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns a slice of bytes written to the buffer.
|
||||||
|
func (b *WriteAtBuffer) Bytes() []byte {
|
||||||
|
b.m.Lock()
|
||||||
|
defer b.m.Unlock()
|
||||||
|
return b.buf
|
||||||
|
}
|
8
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/version.go
generated
vendored
Normal file
8
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/aws/version.go
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// Package aws provides core functionality for making requests to AWS services.
|
||||||
|
package aws
|
||||||
|
|
||||||
|
// SDKName is the name of this AWS SDK
|
||||||
|
const SDKName = "aws-sdk-go"
|
||||||
|
|
||||||
|
// SDKVersion is the version of this SDK
|
||||||
|
const SDKVersion = "1.6.24"
|
35
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/build.go
generated
vendored
Normal file
35
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/build.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// Package ec2query provides serialization of AWS EC2 requests and responses.
|
||||||
|
package ec2query
|
||||||
|
|
||||||
|
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/ec2.json build_test.go
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol/query/queryutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BuildHandler is a named request handler for building ec2query protocol requests
|
||||||
|
var BuildHandler = request.NamedHandler{Name: "awssdk.ec2query.Build", Fn: Build}
|
||||||
|
|
||||||
|
// Build builds a request for the EC2 protocol.
|
||||||
|
func Build(r *request.Request) {
|
||||||
|
body := url.Values{
|
||||||
|
"Action": {r.Operation.Name},
|
||||||
|
"Version": {r.ClientInfo.APIVersion},
|
||||||
|
}
|
||||||
|
if err := queryutil.Parse(body, r.Params, true); err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed encoding EC2 Query request", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.ExpireTime == 0 {
|
||||||
|
r.HTTPRequest.Method = "POST"
|
||||||
|
r.HTTPRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
|
||||||
|
r.SetBufferBody([]byte(body.Encode()))
|
||||||
|
} else { // This is a pre-signed request
|
||||||
|
r.HTTPRequest.Method = "GET"
|
||||||
|
r.HTTPRequest.URL.RawQuery = body.Encode()
|
||||||
|
}
|
||||||
|
}
|
63
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/unmarshal.go
generated
vendored
Normal file
63
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/unmarshal.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
package ec2query
|
||||||
|
|
||||||
|
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/ec2.json unmarshal_test.go
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnmarshalHandler is a named request handler for unmarshaling ec2query protocol requests
|
||||||
|
var UnmarshalHandler = request.NamedHandler{Name: "awssdk.ec2query.Unmarshal", Fn: Unmarshal}
|
||||||
|
|
||||||
|
// UnmarshalMetaHandler is a named request handler for unmarshaling ec2query protocol request metadata
|
||||||
|
var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.ec2query.UnmarshalMeta", Fn: UnmarshalMeta}
|
||||||
|
|
||||||
|
// UnmarshalErrorHandler is a named request handler for unmarshaling ec2query protocol request errors
|
||||||
|
var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.ec2query.UnmarshalError", Fn: UnmarshalError}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals a response body for the EC2 protocol.
|
||||||
|
func Unmarshal(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
if r.DataFilled() {
|
||||||
|
decoder := xml.NewDecoder(r.HTTPResponse.Body)
|
||||||
|
err := xmlutil.UnmarshalXML(r.Data, decoder, "")
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed decoding EC2 Query response", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMeta unmarshals response headers for the EC2 protocol.
|
||||||
|
func UnmarshalMeta(r *request.Request) {
|
||||||
|
// TODO implement unmarshaling of request IDs
|
||||||
|
}
|
||||||
|
|
||||||
|
type xmlErrorResponse struct {
|
||||||
|
XMLName xml.Name `xml:"Response"`
|
||||||
|
Code string `xml:"Errors>Error>Code"`
|
||||||
|
Message string `xml:"Errors>Error>Message"`
|
||||||
|
RequestID string `xml:"RequestID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalError unmarshals a response error for the EC2 protocol.
|
||||||
|
func UnmarshalError(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
|
||||||
|
resp := &xmlErrorResponse{}
|
||||||
|
err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed decoding EC2 Query error response", err)
|
||||||
|
} else {
|
||||||
|
r.Error = awserr.NewRequestFailure(
|
||||||
|
awserr.New(resp.Code, resp.Message, nil),
|
||||||
|
r.HTTPResponse.StatusCode,
|
||||||
|
resp.RequestID,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
75
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/idempotency.go
generated
vendored
Normal file
75
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/idempotency.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RandReader is the random reader the protocol package will use to read
|
||||||
|
// random bytes from. This is exported for testing, and should not be used.
|
||||||
|
var RandReader = rand.Reader
|
||||||
|
|
||||||
|
const idempotencyTokenFillTag = `idempotencyToken`
|
||||||
|
|
||||||
|
// CanSetIdempotencyToken returns true if the struct field should be
|
||||||
|
// automatically populated with a Idempotency token.
|
||||||
|
//
|
||||||
|
// Only *string and string type fields that are tagged with idempotencyToken
|
||||||
|
// which are not already set can be auto filled.
|
||||||
|
func CanSetIdempotencyToken(v reflect.Value, f reflect.StructField) bool {
|
||||||
|
switch u := v.Interface().(type) {
|
||||||
|
// To auto fill an Idempotency token the field must be a string,
|
||||||
|
// tagged for auto fill, and have a zero value.
|
||||||
|
case *string:
|
||||||
|
return u == nil && len(f.Tag.Get(idempotencyTokenFillTag)) != 0
|
||||||
|
case string:
|
||||||
|
return len(u) == 0 && len(f.Tag.Get(idempotencyTokenFillTag)) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIdempotencyToken returns a randomly generated idempotency token.
|
||||||
|
func GetIdempotencyToken() string {
|
||||||
|
b := make([]byte, 16)
|
||||||
|
RandReader.Read(b)
|
||||||
|
|
||||||
|
return UUIDVersion4(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIdempotencyToken will set the value provided with a Idempotency Token.
|
||||||
|
// Given that the value can be set. Will panic if value is not setable.
|
||||||
|
func SetIdempotencyToken(v reflect.Value) {
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
if v.IsNil() && v.CanSet() {
|
||||||
|
v.Set(reflect.New(v.Type().Elem()))
|
||||||
|
}
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
v = reflect.Indirect(v)
|
||||||
|
|
||||||
|
if !v.CanSet() {
|
||||||
|
panic(fmt.Sprintf("unable to set idempotnecy token %v", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]byte, 16)
|
||||||
|
_, err := rand.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
// TODO handle error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Set(reflect.ValueOf(UUIDVersion4(b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UUIDVersion4 returns a Version 4 random UUID from the byte slice provided
|
||||||
|
func UUIDVersion4(u []byte) string {
|
||||||
|
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29
|
||||||
|
// 13th character is "4"
|
||||||
|
u[6] = (u[6] | 0x40) & 0x4F
|
||||||
|
// 17th character is "8", "9", "a", or "b"
|
||||||
|
u[8] = (u[8] | 0x80) & 0xBF
|
||||||
|
|
||||||
|
return fmt.Sprintf(`%X-%X-%X-%X-%X`, u[0:4], u[4:6], u[6:8], u[8:10], u[10:])
|
||||||
|
}
|
36
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/query/build.go
generated
vendored
Normal file
36
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/query/build.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Package query provides serialization of AWS query requests, and responses.
|
||||||
|
package query
|
||||||
|
|
||||||
|
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/query.json build_test.go
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol/query/queryutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BuildHandler is a named request handler for building query protocol requests
|
||||||
|
var BuildHandler = request.NamedHandler{Name: "awssdk.query.Build", Fn: Build}
|
||||||
|
|
||||||
|
// Build builds a request for an AWS Query service.
|
||||||
|
func Build(r *request.Request) {
|
||||||
|
body := url.Values{
|
||||||
|
"Action": {r.Operation.Name},
|
||||||
|
"Version": {r.ClientInfo.APIVersion},
|
||||||
|
}
|
||||||
|
if err := queryutil.Parse(body, r.Params, false); err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed encoding Query request", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.ExpireTime == 0 {
|
||||||
|
r.HTTPRequest.Method = "POST"
|
||||||
|
r.HTTPRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
|
||||||
|
r.SetBufferBody([]byte(body.Encode()))
|
||||||
|
} else { // This is a pre-signed request
|
||||||
|
r.HTTPRequest.Method = "GET"
|
||||||
|
r.HTTPRequest.URL.RawQuery = body.Encode()
|
||||||
|
}
|
||||||
|
}
|
234
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go
generated
vendored
Normal file
234
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go
generated
vendored
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
package queryutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse parses an object i and fills a url.Values object. The isEC2 flag
|
||||||
|
// indicates if this is the EC2 Query sub-protocol.
|
||||||
|
func Parse(body url.Values, i interface{}, isEC2 bool) error {
|
||||||
|
q := queryParser{isEC2: isEC2}
|
||||||
|
return q.parseValue(body, reflect.ValueOf(i), "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func elemOf(value reflect.Value) reflect.Value {
|
||||||
|
for value.Kind() == reflect.Ptr {
|
||||||
|
value = value.Elem()
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
type queryParser struct {
|
||||||
|
isEC2 bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *queryParser) parseValue(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
|
||||||
|
value = elemOf(value)
|
||||||
|
|
||||||
|
// no need to handle zero values
|
||||||
|
if !value.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t := tag.Get("type")
|
||||||
|
if t == "" {
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
t = "structure"
|
||||||
|
case reflect.Slice:
|
||||||
|
t = "list"
|
||||||
|
case reflect.Map:
|
||||||
|
t = "map"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
case "structure":
|
||||||
|
return q.parseStruct(v, value, prefix)
|
||||||
|
case "list":
|
||||||
|
return q.parseList(v, value, prefix, tag)
|
||||||
|
case "map":
|
||||||
|
return q.parseMap(v, value, prefix, tag)
|
||||||
|
default:
|
||||||
|
return q.parseScalar(v, value, prefix, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *queryParser) parseStruct(v url.Values, value reflect.Value, prefix string) error {
|
||||||
|
if !value.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t := value.Type()
|
||||||
|
for i := 0; i < value.NumField(); i++ {
|
||||||
|
elemValue := elemOf(value.Field(i))
|
||||||
|
field := t.Field(i)
|
||||||
|
|
||||||
|
if field.PkgPath != "" {
|
||||||
|
continue // ignore unexported fields
|
||||||
|
}
|
||||||
|
if field.Tag.Get("ignore") != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if protocol.CanSetIdempotencyToken(value.Field(i), field) {
|
||||||
|
token := protocol.GetIdempotencyToken()
|
||||||
|
elemValue = reflect.ValueOf(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
var name string
|
||||||
|
if q.isEC2 {
|
||||||
|
name = field.Tag.Get("queryName")
|
||||||
|
}
|
||||||
|
if name == "" {
|
||||||
|
if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
|
||||||
|
name = field.Tag.Get("locationNameList")
|
||||||
|
} else if locName := field.Tag.Get("locationName"); locName != "" {
|
||||||
|
name = locName
|
||||||
|
}
|
||||||
|
if name != "" && q.isEC2 {
|
||||||
|
name = strings.ToUpper(name[0:1]) + name[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if name == "" {
|
||||||
|
name = field.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefix != "" {
|
||||||
|
name = prefix + "." + name
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := q.parseValue(v, elemValue, name, field.Tag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *queryParser) parseList(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
|
||||||
|
// If it's empty, generate an empty value
|
||||||
|
if !value.IsNil() && value.Len() == 0 {
|
||||||
|
v.Set(prefix, "")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for unflattened list member
|
||||||
|
if !q.isEC2 && tag.Get("flattened") == "" {
|
||||||
|
prefix += ".member"
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < value.Len(); i++ {
|
||||||
|
slicePrefix := prefix
|
||||||
|
if slicePrefix == "" {
|
||||||
|
slicePrefix = strconv.Itoa(i + 1)
|
||||||
|
} else {
|
||||||
|
slicePrefix = slicePrefix + "." + strconv.Itoa(i+1)
|
||||||
|
}
|
||||||
|
if err := q.parseValue(v, value.Index(i), slicePrefix, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *queryParser) parseMap(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
|
||||||
|
// If it's empty, generate an empty value
|
||||||
|
if !value.IsNil() && value.Len() == 0 {
|
||||||
|
v.Set(prefix, "")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for unflattened list member
|
||||||
|
if !q.isEC2 && tag.Get("flattened") == "" {
|
||||||
|
prefix += ".entry"
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort keys for improved serialization consistency.
|
||||||
|
// this is not strictly necessary for protocol support.
|
||||||
|
mapKeyValues := value.MapKeys()
|
||||||
|
mapKeys := map[string]reflect.Value{}
|
||||||
|
mapKeyNames := make([]string, len(mapKeyValues))
|
||||||
|
for i, mapKey := range mapKeyValues {
|
||||||
|
name := mapKey.String()
|
||||||
|
mapKeys[name] = mapKey
|
||||||
|
mapKeyNames[i] = name
|
||||||
|
}
|
||||||
|
sort.Strings(mapKeyNames)
|
||||||
|
|
||||||
|
for i, mapKeyName := range mapKeyNames {
|
||||||
|
mapKey := mapKeys[mapKeyName]
|
||||||
|
mapValue := value.MapIndex(mapKey)
|
||||||
|
|
||||||
|
kname := tag.Get("locationNameKey")
|
||||||
|
if kname == "" {
|
||||||
|
kname = "key"
|
||||||
|
}
|
||||||
|
vname := tag.Get("locationNameValue")
|
||||||
|
if vname == "" {
|
||||||
|
vname = "value"
|
||||||
|
}
|
||||||
|
|
||||||
|
// serialize key
|
||||||
|
var keyName string
|
||||||
|
if prefix == "" {
|
||||||
|
keyName = strconv.Itoa(i+1) + "." + kname
|
||||||
|
} else {
|
||||||
|
keyName = prefix + "." + strconv.Itoa(i+1) + "." + kname
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := q.parseValue(v, mapKey, keyName, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// serialize value
|
||||||
|
var valueName string
|
||||||
|
if prefix == "" {
|
||||||
|
valueName = strconv.Itoa(i+1) + "." + vname
|
||||||
|
} else {
|
||||||
|
valueName = prefix + "." + strconv.Itoa(i+1) + "." + vname
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := q.parseValue(v, mapValue, valueName, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *queryParser) parseScalar(v url.Values, r reflect.Value, name string, tag reflect.StructTag) error {
|
||||||
|
switch value := r.Interface().(type) {
|
||||||
|
case string:
|
||||||
|
v.Set(name, value)
|
||||||
|
case []byte:
|
||||||
|
if !r.IsNil() {
|
||||||
|
v.Set(name, base64.StdEncoding.EncodeToString(value))
|
||||||
|
}
|
||||||
|
case bool:
|
||||||
|
v.Set(name, strconv.FormatBool(value))
|
||||||
|
case int64:
|
||||||
|
v.Set(name, strconv.FormatInt(value, 10))
|
||||||
|
case int:
|
||||||
|
v.Set(name, strconv.Itoa(value))
|
||||||
|
case float64:
|
||||||
|
v.Set(name, strconv.FormatFloat(value, 'f', -1, 64))
|
||||||
|
case float32:
|
||||||
|
v.Set(name, strconv.FormatFloat(float64(value), 'f', -1, 32))
|
||||||
|
case time.Time:
|
||||||
|
const ISO8601UTC = "2006-01-02T15:04:05Z"
|
||||||
|
v.Set(name, value.UTC().Format(ISO8601UTC))
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported value for param %s: %v (%s)", name, r.Interface(), r.Type().Name())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
35
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal.go
generated
vendored
Normal file
35
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package query
|
||||||
|
|
||||||
|
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/query.json unmarshal_test.go
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnmarshalHandler is a named request handler for unmarshaling query protocol requests
|
||||||
|
var UnmarshalHandler = request.NamedHandler{Name: "awssdk.query.Unmarshal", Fn: Unmarshal}
|
||||||
|
|
||||||
|
// UnmarshalMetaHandler is a named request handler for unmarshaling query protocol request metadata
|
||||||
|
var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.query.UnmarshalMeta", Fn: UnmarshalMeta}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals a response for an AWS Query service.
|
||||||
|
func Unmarshal(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
if r.DataFilled() {
|
||||||
|
decoder := xml.NewDecoder(r.HTTPResponse.Body)
|
||||||
|
err := xmlutil.UnmarshalXML(r.Data, decoder, r.Operation.Name+"Result")
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed decoding Query response", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMeta unmarshals header response values for an AWS Query service.
|
||||||
|
func UnmarshalMeta(r *request.Request) {
|
||||||
|
r.RequestID = r.HTTPResponse.Header.Get("X-Amzn-Requestid")
|
||||||
|
}
|
66
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_error.go
generated
vendored
Normal file
66
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_error.go
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
type xmlErrorResponse struct {
|
||||||
|
XMLName xml.Name `xml:"ErrorResponse"`
|
||||||
|
Code string `xml:"Error>Code"`
|
||||||
|
Message string `xml:"Error>Message"`
|
||||||
|
RequestID string `xml:"RequestId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type xmlServiceUnavailableResponse struct {
|
||||||
|
XMLName xml.Name `xml:"ServiceUnavailableException"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalErrorHandler is a name request handler to unmarshal request errors
|
||||||
|
var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.query.UnmarshalError", Fn: UnmarshalError}
|
||||||
|
|
||||||
|
// UnmarshalError unmarshals an error response for an AWS Query service.
|
||||||
|
func UnmarshalError(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
|
||||||
|
bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed to read from query HTTP response body", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// First check for specific error
|
||||||
|
resp := xmlErrorResponse{}
|
||||||
|
decodeErr := xml.Unmarshal(bodyBytes, &resp)
|
||||||
|
if decodeErr == nil {
|
||||||
|
reqID := resp.RequestID
|
||||||
|
if reqID == "" {
|
||||||
|
reqID = r.RequestID
|
||||||
|
}
|
||||||
|
r.Error = awserr.NewRequestFailure(
|
||||||
|
awserr.New(resp.Code, resp.Message, nil),
|
||||||
|
r.HTTPResponse.StatusCode,
|
||||||
|
reqID,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for unhandled error
|
||||||
|
servUnavailResp := xmlServiceUnavailableResponse{}
|
||||||
|
unavailErr := xml.Unmarshal(bodyBytes, &servUnavailResp)
|
||||||
|
if unavailErr == nil {
|
||||||
|
r.Error = awserr.NewRequestFailure(
|
||||||
|
awserr.New("ServiceUnavailableException", "service is unavailable", nil),
|
||||||
|
r.HTTPResponse.StatusCode,
|
||||||
|
r.RequestID,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed to retrieve any error message from the response body
|
||||||
|
r.Error = awserr.New("SerializationError",
|
||||||
|
"failed to decode query XML error response", decodeErr)
|
||||||
|
}
|
274
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go
generated
vendored
Normal file
274
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go
generated
vendored
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
// Package rest provides RESTful serialization of AWS requests and responses.
|
||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"reflect"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC822 returns an RFC822 formatted timestamp for AWS protocols
|
||||||
|
const RFC822 = "Mon, 2 Jan 2006 15:04:05 GMT"
|
||||||
|
|
||||||
|
// Whether the byte value can be sent without escaping in AWS URLs
|
||||||
|
var noEscape [256]bool
|
||||||
|
|
||||||
|
var errValueNotSet = fmt.Errorf("value not set")
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := 0; i < len(noEscape); i++ {
|
||||||
|
// AWS expects every character except these to be escaped
|
||||||
|
noEscape[i] = (i >= 'A' && i <= 'Z') ||
|
||||||
|
(i >= 'a' && i <= 'z') ||
|
||||||
|
(i >= '0' && i <= '9') ||
|
||||||
|
i == '-' ||
|
||||||
|
i == '.' ||
|
||||||
|
i == '_' ||
|
||||||
|
i == '~'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildHandler is a named request handler for building rest protocol requests
|
||||||
|
var BuildHandler = request.NamedHandler{Name: "awssdk.rest.Build", Fn: Build}
|
||||||
|
|
||||||
|
// Build builds the REST component of a service request.
|
||||||
|
func Build(r *request.Request) {
|
||||||
|
if r.ParamsFilled() {
|
||||||
|
v := reflect.ValueOf(r.Params).Elem()
|
||||||
|
buildLocationElements(r, v, false)
|
||||||
|
buildBody(r, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildAsGET builds the REST component of a service request with the ability to hoist
|
||||||
|
// data from the body.
|
||||||
|
func BuildAsGET(r *request.Request) {
|
||||||
|
if r.ParamsFilled() {
|
||||||
|
v := reflect.ValueOf(r.Params).Elem()
|
||||||
|
buildLocationElements(r, v, true)
|
||||||
|
buildBody(r, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildLocationElements(r *request.Request, v reflect.Value, buildGETQuery bool) {
|
||||||
|
query := r.HTTPRequest.URL.Query()
|
||||||
|
|
||||||
|
// Setup the raw path to match the base path pattern. This is needed
|
||||||
|
// so that when the path is mutated a custom escaped version can be
|
||||||
|
// stored in RawPath that will be used by the Go client.
|
||||||
|
r.HTTPRequest.URL.RawPath = r.HTTPRequest.URL.Path
|
||||||
|
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
m := v.Field(i)
|
||||||
|
if n := v.Type().Field(i).Name; n[0:1] == strings.ToLower(n[0:1]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.IsValid() {
|
||||||
|
field := v.Type().Field(i)
|
||||||
|
name := field.Tag.Get("locationName")
|
||||||
|
if name == "" {
|
||||||
|
name = field.Name
|
||||||
|
}
|
||||||
|
if m.Kind() == reflect.Ptr {
|
||||||
|
m = m.Elem()
|
||||||
|
}
|
||||||
|
if !m.IsValid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if field.Tag.Get("ignore") != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
switch field.Tag.Get("location") {
|
||||||
|
case "headers": // header maps
|
||||||
|
err = buildHeaderMap(&r.HTTPRequest.Header, m, field.Tag.Get("locationName"))
|
||||||
|
case "header":
|
||||||
|
err = buildHeader(&r.HTTPRequest.Header, m, name)
|
||||||
|
case "uri":
|
||||||
|
err = buildURI(r.HTTPRequest.URL, m, name)
|
||||||
|
case "querystring":
|
||||||
|
err = buildQueryString(query, m, name)
|
||||||
|
default:
|
||||||
|
if buildGETQuery {
|
||||||
|
err = buildQueryString(query, m, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.Error = err
|
||||||
|
}
|
||||||
|
if r.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.HTTPRequest.URL.RawQuery = query.Encode()
|
||||||
|
if !aws.BoolValue(r.Config.DisableRestProtocolURICleaning) {
|
||||||
|
cleanPath(r.HTTPRequest.URL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildBody(r *request.Request, v reflect.Value) {
|
||||||
|
if field, ok := v.Type().FieldByName("_"); ok {
|
||||||
|
if payloadName := field.Tag.Get("payload"); payloadName != "" {
|
||||||
|
pfield, _ := v.Type().FieldByName(payloadName)
|
||||||
|
if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" {
|
||||||
|
payload := reflect.Indirect(v.FieldByName(payloadName))
|
||||||
|
if payload.IsValid() && payload.Interface() != nil {
|
||||||
|
switch reader := payload.Interface().(type) {
|
||||||
|
case io.ReadSeeker:
|
||||||
|
r.SetReaderBody(reader)
|
||||||
|
case []byte:
|
||||||
|
r.SetBufferBody(reader)
|
||||||
|
case string:
|
||||||
|
r.SetStringBody(reader)
|
||||||
|
default:
|
||||||
|
r.Error = awserr.New("SerializationError",
|
||||||
|
"failed to encode REST request",
|
||||||
|
fmt.Errorf("unknown payload type %s", payload.Type()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildHeader(header *http.Header, v reflect.Value, name string) error {
|
||||||
|
str, err := convertType(v)
|
||||||
|
if err == errValueNotSet {
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return awserr.New("SerializationError", "failed to encode REST request", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
header.Add(name, str)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildHeaderMap(header *http.Header, v reflect.Value, prefix string) error {
|
||||||
|
for _, key := range v.MapKeys() {
|
||||||
|
str, err := convertType(v.MapIndex(key))
|
||||||
|
if err == errValueNotSet {
|
||||||
|
continue
|
||||||
|
} else if err != nil {
|
||||||
|
return awserr.New("SerializationError", "failed to encode REST request", err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
header.Add(prefix+key.String(), str)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildURI(u *url.URL, v reflect.Value, name string) error {
|
||||||
|
value, err := convertType(v)
|
||||||
|
if err == errValueNotSet {
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return awserr.New("SerializationError", "failed to encode REST request", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Path = strings.Replace(u.Path, "{"+name+"}", value, -1)
|
||||||
|
u.Path = strings.Replace(u.Path, "{"+name+"+}", value, -1)
|
||||||
|
|
||||||
|
u.RawPath = strings.Replace(u.RawPath, "{"+name+"}", EscapePath(value, true), -1)
|
||||||
|
u.RawPath = strings.Replace(u.RawPath, "{"+name+"+}", EscapePath(value, false), -1)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildQueryString(query url.Values, v reflect.Value, name string) error {
|
||||||
|
switch value := v.Interface().(type) {
|
||||||
|
case []*string:
|
||||||
|
for _, item := range value {
|
||||||
|
query.Add(name, *item)
|
||||||
|
}
|
||||||
|
case map[string]*string:
|
||||||
|
for key, item := range value {
|
||||||
|
query.Add(key, *item)
|
||||||
|
}
|
||||||
|
case map[string][]*string:
|
||||||
|
for key, items := range value {
|
||||||
|
for _, item := range items {
|
||||||
|
query.Add(key, *item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
str, err := convertType(v)
|
||||||
|
if err == errValueNotSet {
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return awserr.New("SerializationError", "failed to encode REST request", err)
|
||||||
|
}
|
||||||
|
query.Set(name, str)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanPath(u *url.URL) {
|
||||||
|
hasSlash := strings.HasSuffix(u.Path, "/")
|
||||||
|
|
||||||
|
// clean up path, removing duplicate `/`
|
||||||
|
u.Path = path.Clean(u.Path)
|
||||||
|
u.RawPath = path.Clean(u.RawPath)
|
||||||
|
|
||||||
|
if hasSlash && !strings.HasSuffix(u.Path, "/") {
|
||||||
|
u.Path += "/"
|
||||||
|
u.RawPath += "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EscapePath escapes part of a URL path in Amazon style
|
||||||
|
func EscapePath(path string, encodeSep bool) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for i := 0; i < len(path); i++ {
|
||||||
|
c := path[i]
|
||||||
|
if noEscape[c] || (c == '/' && !encodeSep) {
|
||||||
|
buf.WriteByte(c)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(&buf, "%%%02X", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertType(v reflect.Value) (string, error) {
|
||||||
|
v = reflect.Indirect(v)
|
||||||
|
if !v.IsValid() {
|
||||||
|
return "", errValueNotSet
|
||||||
|
}
|
||||||
|
|
||||||
|
var str string
|
||||||
|
switch value := v.Interface().(type) {
|
||||||
|
case string:
|
||||||
|
str = value
|
||||||
|
case []byte:
|
||||||
|
str = base64.StdEncoding.EncodeToString(value)
|
||||||
|
case bool:
|
||||||
|
str = strconv.FormatBool(value)
|
||||||
|
case int64:
|
||||||
|
str = strconv.FormatInt(value, 10)
|
||||||
|
case float64:
|
||||||
|
str = strconv.FormatFloat(value, 'f', -1, 64)
|
||||||
|
case time.Time:
|
||||||
|
str = value.UTC().Format(RFC822)
|
||||||
|
default:
|
||||||
|
err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return str, nil
|
||||||
|
}
|
45
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/payload.go
generated
vendored
Normal file
45
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/payload.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package rest
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// PayloadMember returns the payload field member of i if there is one, or nil.
|
||||||
|
func PayloadMember(i interface{}) interface{} {
|
||||||
|
if i == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v := reflect.ValueOf(i).Elem()
|
||||||
|
if !v.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if field, ok := v.Type().FieldByName("_"); ok {
|
||||||
|
if payloadName := field.Tag.Get("payload"); payloadName != "" {
|
||||||
|
field, _ := v.Type().FieldByName(payloadName)
|
||||||
|
if field.Tag.Get("type") != "structure" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := v.FieldByName(payloadName)
|
||||||
|
if payload.IsValid() || (payload.Kind() == reflect.Ptr && !payload.IsNil()) {
|
||||||
|
return payload.Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PayloadType returns the type of a payload field member of i if there is one, or "".
|
||||||
|
func PayloadType(i interface{}) string {
|
||||||
|
v := reflect.Indirect(reflect.ValueOf(i))
|
||||||
|
if !v.IsValid() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if field, ok := v.Type().FieldByName("_"); ok {
|
||||||
|
if payloadName := field.Tag.Get("payload"); payloadName != "" {
|
||||||
|
if member, ok := v.Type().FieldByName(payloadName); ok {
|
||||||
|
return member.Tag.Get("type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
204
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go
generated
vendored
Normal file
204
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go
generated
vendored
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnmarshalHandler is a named request handler for unmarshaling rest protocol requests
|
||||||
|
var UnmarshalHandler = request.NamedHandler{Name: "awssdk.rest.Unmarshal", Fn: Unmarshal}
|
||||||
|
|
||||||
|
// UnmarshalMetaHandler is a named request handler for unmarshaling rest protocol request metadata
|
||||||
|
var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.rest.UnmarshalMeta", Fn: UnmarshalMeta}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals the REST component of a response in a REST service.
|
||||||
|
func Unmarshal(r *request.Request) {
|
||||||
|
if r.DataFilled() {
|
||||||
|
v := reflect.Indirect(reflect.ValueOf(r.Data))
|
||||||
|
unmarshalBody(r, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMeta unmarshals the REST metadata of a response in a REST service
|
||||||
|
func UnmarshalMeta(r *request.Request) {
|
||||||
|
r.RequestID = r.HTTPResponse.Header.Get("X-Amzn-Requestid")
|
||||||
|
if r.RequestID == "" {
|
||||||
|
// Alternative version of request id in the header
|
||||||
|
r.RequestID = r.HTTPResponse.Header.Get("X-Amz-Request-Id")
|
||||||
|
}
|
||||||
|
if r.DataFilled() {
|
||||||
|
v := reflect.Indirect(reflect.ValueOf(r.Data))
|
||||||
|
unmarshalLocationElements(r, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalBody(r *request.Request, v reflect.Value) {
|
||||||
|
if field, ok := v.Type().FieldByName("_"); ok {
|
||||||
|
if payloadName := field.Tag.Get("payload"); payloadName != "" {
|
||||||
|
pfield, _ := v.Type().FieldByName(payloadName)
|
||||||
|
if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" {
|
||||||
|
payload := v.FieldByName(payloadName)
|
||||||
|
if payload.IsValid() {
|
||||||
|
switch payload.Interface().(type) {
|
||||||
|
case []byte:
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed to decode REST response", err)
|
||||||
|
} else {
|
||||||
|
payload.Set(reflect.ValueOf(b))
|
||||||
|
}
|
||||||
|
case *string:
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed to decode REST response", err)
|
||||||
|
} else {
|
||||||
|
str := string(b)
|
||||||
|
payload.Set(reflect.ValueOf(&str))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
switch payload.Type().String() {
|
||||||
|
case "io.ReadCloser":
|
||||||
|
payload.Set(reflect.ValueOf(r.HTTPResponse.Body))
|
||||||
|
case "io.ReadSeeker":
|
||||||
|
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError",
|
||||||
|
"failed to read response body", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
payload.Set(reflect.ValueOf(ioutil.NopCloser(bytes.NewReader(b))))
|
||||||
|
default:
|
||||||
|
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
r.Error = awserr.New("SerializationError",
|
||||||
|
"failed to decode REST response",
|
||||||
|
fmt.Errorf("unknown payload type %s", payload.Type()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalLocationElements(r *request.Request, v reflect.Value) {
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
m, field := v.Field(i), v.Type().Field(i)
|
||||||
|
if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.IsValid() {
|
||||||
|
name := field.Tag.Get("locationName")
|
||||||
|
if name == "" {
|
||||||
|
name = field.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
switch field.Tag.Get("location") {
|
||||||
|
case "statusCode":
|
||||||
|
unmarshalStatusCode(m, r.HTTPResponse.StatusCode)
|
||||||
|
case "header":
|
||||||
|
err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name))
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed to decode REST response", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "headers":
|
||||||
|
prefix := field.Tag.Get("locationName")
|
||||||
|
err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.New("SerializationError", "failed to decode REST response", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalStatusCode(v reflect.Value, statusCode int) {
|
||||||
|
if !v.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v.Interface().(type) {
|
||||||
|
case *int64:
|
||||||
|
s := int64(statusCode)
|
||||||
|
v.Set(reflect.ValueOf(&s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) error {
|
||||||
|
switch r.Interface().(type) {
|
||||||
|
case map[string]*string: // we only support string map value types
|
||||||
|
out := map[string]*string{}
|
||||||
|
for k, v := range headers {
|
||||||
|
k = http.CanonicalHeaderKey(k)
|
||||||
|
if strings.HasPrefix(strings.ToLower(k), strings.ToLower(prefix)) {
|
||||||
|
out[k[len(prefix):]] = &v[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.Set(reflect.ValueOf(out))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalHeader(v reflect.Value, header string) error {
|
||||||
|
if !v.IsValid() || (header == "" && v.Elem().Kind() != reflect.String) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v.Interface().(type) {
|
||||||
|
case *string:
|
||||||
|
v.Set(reflect.ValueOf(&header))
|
||||||
|
case []byte:
|
||||||
|
b, err := base64.StdEncoding.DecodeString(header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set(reflect.ValueOf(&b))
|
||||||
|
case *bool:
|
||||||
|
b, err := strconv.ParseBool(header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set(reflect.ValueOf(&b))
|
||||||
|
case *int64:
|
||||||
|
i, err := strconv.ParseInt(header, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set(reflect.ValueOf(&i))
|
||||||
|
case *float64:
|
||||||
|
f, err := strconv.ParseFloat(header, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set(reflect.ValueOf(&f))
|
||||||
|
case *time.Time:
|
||||||
|
t, err := time.Parse(RFC822, header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set(reflect.ValueOf(&t))
|
||||||
|
default:
|
||||||
|
err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
21
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal.go
generated
vendored
Normal file
21
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnmarshalDiscardBodyHandler is a named request handler to empty and close a response's body
|
||||||
|
var UnmarshalDiscardBodyHandler = request.NamedHandler{Name: "awssdk.shared.UnmarshalDiscardBody", Fn: UnmarshalDiscardBody}
|
||||||
|
|
||||||
|
// UnmarshalDiscardBody is a request handler to empty a response's body and closing it.
|
||||||
|
func UnmarshalDiscardBody(r *request.Request) {
|
||||||
|
if r.HTTPResponse == nil || r.HTTPResponse.Body == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
|
||||||
|
r.HTTPResponse.Body.Close()
|
||||||
|
}
|
297
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/build.go
generated
vendored
Normal file
297
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/build.go
generated
vendored
Normal file
|
@ -0,0 +1,297 @@
|
||||||
|
// Package xmlutil provides XML serialization of AWS requests and responses.
|
||||||
|
package xmlutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BuildXML will serialize params into an xml.Encoder.
|
||||||
|
// Error will be returned if the serialization of any of the params or nested values fails.
|
||||||
|
func BuildXML(params interface{}, e *xml.Encoder) error {
|
||||||
|
b := xmlBuilder{encoder: e, namespaces: map[string]string{}}
|
||||||
|
root := NewXMLElement(xml.Name{})
|
||||||
|
if err := b.buildValue(reflect.ValueOf(params), root, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, c := range root.Children {
|
||||||
|
for _, v := range c {
|
||||||
|
return StructToXML(e, v, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the reflection element of a value, if it is a pointer.
|
||||||
|
func elemOf(value reflect.Value) reflect.Value {
|
||||||
|
for value.Kind() == reflect.Ptr {
|
||||||
|
value = value.Elem()
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// A xmlBuilder serializes values from Go code to XML
|
||||||
|
type xmlBuilder struct {
|
||||||
|
encoder *xml.Encoder
|
||||||
|
namespaces map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildValue generic XMLNode builder for any type. Will build value for their specific type
|
||||||
|
// struct, list, map, scalar.
|
||||||
|
//
|
||||||
|
// Also takes a "type" tag value to set what type a value should be converted to XMLNode as. If
|
||||||
|
// type is not provided reflect will be used to determine the value's type.
|
||||||
|
func (b *xmlBuilder) buildValue(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
|
||||||
|
value = elemOf(value)
|
||||||
|
if !value.IsValid() { // no need to handle zero values
|
||||||
|
return nil
|
||||||
|
} else if tag.Get("location") != "" { // don't handle non-body location values
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t := tag.Get("type")
|
||||||
|
if t == "" {
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
t = "structure"
|
||||||
|
case reflect.Slice:
|
||||||
|
t = "list"
|
||||||
|
case reflect.Map:
|
||||||
|
t = "map"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
case "structure":
|
||||||
|
if field, ok := value.Type().FieldByName("_"); ok {
|
||||||
|
tag = tag + reflect.StructTag(" ") + field.Tag
|
||||||
|
}
|
||||||
|
return b.buildStruct(value, current, tag)
|
||||||
|
case "list":
|
||||||
|
return b.buildList(value, current, tag)
|
||||||
|
case "map":
|
||||||
|
return b.buildMap(value, current, tag)
|
||||||
|
default:
|
||||||
|
return b.buildScalar(value, current, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildStruct adds a struct and its fields to the current XMLNode. All fields any any nested
|
||||||
|
// types are converted to XMLNodes also.
|
||||||
|
func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
|
||||||
|
if !value.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldAdded := false
|
||||||
|
|
||||||
|
// unwrap payloads
|
||||||
|
if payload := tag.Get("payload"); payload != "" {
|
||||||
|
field, _ := value.Type().FieldByName(payload)
|
||||||
|
tag = field.Tag
|
||||||
|
value = elemOf(value.FieldByName(payload))
|
||||||
|
|
||||||
|
if !value.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
child := NewXMLElement(xml.Name{Local: tag.Get("locationName")})
|
||||||
|
|
||||||
|
// there is an xmlNamespace associated with this struct
|
||||||
|
if prefix, uri := tag.Get("xmlPrefix"), tag.Get("xmlURI"); uri != "" {
|
||||||
|
ns := xml.Attr{
|
||||||
|
Name: xml.Name{Local: "xmlns"},
|
||||||
|
Value: uri,
|
||||||
|
}
|
||||||
|
if prefix != "" {
|
||||||
|
b.namespaces[prefix] = uri // register the namespace
|
||||||
|
ns.Name.Local = "xmlns:" + prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
child.Attr = append(child.Attr, ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
t := value.Type()
|
||||||
|
for i := 0; i < value.NumField(); i++ {
|
||||||
|
member := elemOf(value.Field(i))
|
||||||
|
field := t.Field(i)
|
||||||
|
|
||||||
|
if field.PkgPath != "" {
|
||||||
|
continue // ignore unexported fields
|
||||||
|
}
|
||||||
|
if field.Tag.Get("ignore") != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mTag := field.Tag
|
||||||
|
if mTag.Get("location") != "" { // skip non-body members
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if protocol.CanSetIdempotencyToken(value.Field(i), field) {
|
||||||
|
token := protocol.GetIdempotencyToken()
|
||||||
|
member = reflect.ValueOf(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
memberName := mTag.Get("locationName")
|
||||||
|
if memberName == "" {
|
||||||
|
memberName = field.Name
|
||||||
|
mTag = reflect.StructTag(string(mTag) + ` locationName:"` + memberName + `"`)
|
||||||
|
}
|
||||||
|
if err := b.buildValue(member, child, mTag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldAdded = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if fieldAdded { // only append this child if we have one ore more valid members
|
||||||
|
current.AddChild(child)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildList adds the value's list items to the current XMLNode as children nodes. All
|
||||||
|
// nested values in the list are converted to XMLNodes also.
|
||||||
|
func (b *xmlBuilder) buildList(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
|
||||||
|
if value.IsNil() { // don't build omitted lists
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for unflattened list member
|
||||||
|
flattened := tag.Get("flattened") != ""
|
||||||
|
|
||||||
|
xname := xml.Name{Local: tag.Get("locationName")}
|
||||||
|
if flattened {
|
||||||
|
for i := 0; i < value.Len(); i++ {
|
||||||
|
child := NewXMLElement(xname)
|
||||||
|
current.AddChild(child)
|
||||||
|
if err := b.buildValue(value.Index(i), child, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
list := NewXMLElement(xname)
|
||||||
|
current.AddChild(list)
|
||||||
|
|
||||||
|
for i := 0; i < value.Len(); i++ {
|
||||||
|
iname := tag.Get("locationNameList")
|
||||||
|
if iname == "" {
|
||||||
|
iname = "member"
|
||||||
|
}
|
||||||
|
|
||||||
|
child := NewXMLElement(xml.Name{Local: iname})
|
||||||
|
list.AddChild(child)
|
||||||
|
if err := b.buildValue(value.Index(i), child, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildMap adds the value's key/value pairs to the current XMLNode as children nodes. All
|
||||||
|
// nested values in the map are converted to XMLNodes also.
|
||||||
|
//
|
||||||
|
// Error will be returned if it is unable to build the map's values into XMLNodes
|
||||||
|
func (b *xmlBuilder) buildMap(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
|
||||||
|
if value.IsNil() { // don't build omitted maps
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
maproot := NewXMLElement(xml.Name{Local: tag.Get("locationName")})
|
||||||
|
current.AddChild(maproot)
|
||||||
|
current = maproot
|
||||||
|
|
||||||
|
kname, vname := "key", "value"
|
||||||
|
if n := tag.Get("locationNameKey"); n != "" {
|
||||||
|
kname = n
|
||||||
|
}
|
||||||
|
if n := tag.Get("locationNameValue"); n != "" {
|
||||||
|
vname = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// sorting is not required for compliance, but it makes testing easier
|
||||||
|
keys := make([]string, value.Len())
|
||||||
|
for i, k := range value.MapKeys() {
|
||||||
|
keys[i] = k.String()
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
v := value.MapIndex(reflect.ValueOf(k))
|
||||||
|
|
||||||
|
mapcur := current
|
||||||
|
if tag.Get("flattened") == "" { // add "entry" tag to non-flat maps
|
||||||
|
child := NewXMLElement(xml.Name{Local: "entry"})
|
||||||
|
mapcur.AddChild(child)
|
||||||
|
mapcur = child
|
||||||
|
}
|
||||||
|
|
||||||
|
kchild := NewXMLElement(xml.Name{Local: kname})
|
||||||
|
kchild.Text = k
|
||||||
|
vchild := NewXMLElement(xml.Name{Local: vname})
|
||||||
|
mapcur.AddChild(kchild)
|
||||||
|
mapcur.AddChild(vchild)
|
||||||
|
|
||||||
|
if err := b.buildValue(v, vchild, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildScalar will convert the value into a string and append it as a attribute or child
|
||||||
|
// of the current XMLNode.
|
||||||
|
//
|
||||||
|
// The value will be added as an attribute if tag contains a "xmlAttribute" attribute value.
|
||||||
|
//
|
||||||
|
// Error will be returned if the value type is unsupported.
|
||||||
|
func (b *xmlBuilder) buildScalar(value reflect.Value, current *XMLNode, tag reflect.StructTag) error {
|
||||||
|
var str string
|
||||||
|
switch converted := value.Interface().(type) {
|
||||||
|
case string:
|
||||||
|
str = converted
|
||||||
|
case []byte:
|
||||||
|
if !value.IsNil() {
|
||||||
|
str = base64.StdEncoding.EncodeToString(converted)
|
||||||
|
}
|
||||||
|
case bool:
|
||||||
|
str = strconv.FormatBool(converted)
|
||||||
|
case int64:
|
||||||
|
str = strconv.FormatInt(converted, 10)
|
||||||
|
case int:
|
||||||
|
str = strconv.Itoa(converted)
|
||||||
|
case float64:
|
||||||
|
str = strconv.FormatFloat(converted, 'f', -1, 64)
|
||||||
|
case float32:
|
||||||
|
str = strconv.FormatFloat(float64(converted), 'f', -1, 32)
|
||||||
|
case time.Time:
|
||||||
|
const ISO8601UTC = "2006-01-02T15:04:05Z"
|
||||||
|
str = converted.UTC().Format(ISO8601UTC)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported value for param %s: %v (%s)",
|
||||||
|
tag.Get("locationName"), value.Interface(), value.Type().Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
xname := xml.Name{Local: tag.Get("locationName")}
|
||||||
|
if tag.Get("xmlAttribute") != "" { // put into current node's attribute list
|
||||||
|
attr := xml.Attr{Name: xname, Value: str}
|
||||||
|
current.Attr = append(current.Attr, attr)
|
||||||
|
} else { // regular text node
|
||||||
|
current.AddChild(&XMLNode{Name: xname, Text: str})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
257
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go
generated
vendored
Normal file
257
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go
generated
vendored
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
package xmlutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnmarshalXML deserializes an xml.Decoder into the container v. V
|
||||||
|
// needs to match the shape of the XML expected to be decoded.
|
||||||
|
// If the shape doesn't match unmarshaling will fail.
|
||||||
|
func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
|
||||||
|
n, _ := XMLToStruct(d, nil)
|
||||||
|
if n.Children != nil {
|
||||||
|
for _, root := range n.Children {
|
||||||
|
for _, c := range root {
|
||||||
|
if wrappedChild, ok := c.Children[wrapper]; ok {
|
||||||
|
c = wrappedChild[0] // pull out wrapped element
|
||||||
|
}
|
||||||
|
|
||||||
|
err := parse(reflect.ValueOf(v), c, "")
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
|
||||||
|
// will be used to determine the type from r.
|
||||||
|
func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||||
|
rtype := r.Type()
|
||||||
|
if rtype.Kind() == reflect.Ptr {
|
||||||
|
rtype = rtype.Elem() // check kind of actual element type
|
||||||
|
}
|
||||||
|
|
||||||
|
t := tag.Get("type")
|
||||||
|
if t == "" {
|
||||||
|
switch rtype.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
t = "structure"
|
||||||
|
case reflect.Slice:
|
||||||
|
t = "list"
|
||||||
|
case reflect.Map:
|
||||||
|
t = "map"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
case "structure":
|
||||||
|
if field, ok := rtype.FieldByName("_"); ok {
|
||||||
|
tag = field.Tag
|
||||||
|
}
|
||||||
|
return parseStruct(r, node, tag)
|
||||||
|
case "list":
|
||||||
|
return parseList(r, node, tag)
|
||||||
|
case "map":
|
||||||
|
return parseMap(r, node, tag)
|
||||||
|
default:
|
||||||
|
return parseScalar(r, node, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseStruct deserializes a structure and its fields from an XMLNode. Any nested
|
||||||
|
// types in the structure will also be deserialized.
|
||||||
|
func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||||
|
t := r.Type()
|
||||||
|
if r.Kind() == reflect.Ptr {
|
||||||
|
if r.IsNil() { // create the structure if it's nil
|
||||||
|
s := reflect.New(r.Type().Elem())
|
||||||
|
r.Set(s)
|
||||||
|
r = s
|
||||||
|
}
|
||||||
|
|
||||||
|
r = r.Elem()
|
||||||
|
t = t.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// unwrap any payloads
|
||||||
|
if payload := tag.Get("payload"); payload != "" {
|
||||||
|
field, _ := t.FieldByName(payload)
|
||||||
|
return parseStruct(r.FieldByName(payload), node, field.Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
if c := field.Name[0:1]; strings.ToLower(c) == c {
|
||||||
|
continue // ignore unexported fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// figure out what this field is called
|
||||||
|
name := field.Name
|
||||||
|
if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
|
||||||
|
name = field.Tag.Get("locationNameList")
|
||||||
|
} else if locName := field.Tag.Get("locationName"); locName != "" {
|
||||||
|
name = locName
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to find the field by name in elements
|
||||||
|
elems := node.Children[name]
|
||||||
|
|
||||||
|
if elems == nil { // try to find the field in attributes
|
||||||
|
if val, ok := node.findElem(name); ok {
|
||||||
|
elems = []*XMLNode{{Text: val}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
member := r.FieldByName(field.Name)
|
||||||
|
for _, elem := range elems {
|
||||||
|
err := parse(member, elem, field.Tag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseList deserializes a list of values from an XML node. Each list entry
|
||||||
|
// will also be deserialized.
|
||||||
|
func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||||
|
t := r.Type()
|
||||||
|
|
||||||
|
if tag.Get("flattened") == "" { // look at all item entries
|
||||||
|
mname := "member"
|
||||||
|
if name := tag.Get("locationNameList"); name != "" {
|
||||||
|
mname = name
|
||||||
|
}
|
||||||
|
|
||||||
|
if Children, ok := node.Children[mname]; ok {
|
||||||
|
if r.IsNil() {
|
||||||
|
r.Set(reflect.MakeSlice(t, len(Children), len(Children)))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range Children {
|
||||||
|
err := parse(r.Index(i), c, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // flattened list means this is a single element
|
||||||
|
if r.IsNil() {
|
||||||
|
r.Set(reflect.MakeSlice(t, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
childR := reflect.Zero(t.Elem())
|
||||||
|
r.Set(reflect.Append(r, childR))
|
||||||
|
err := parse(r.Index(r.Len()-1), node, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
|
||||||
|
// will also be deserialized as map entries.
|
||||||
|
func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||||
|
if r.IsNil() {
|
||||||
|
r.Set(reflect.MakeMap(r.Type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if tag.Get("flattened") == "" { // look at all child entries
|
||||||
|
for _, entry := range node.Children["entry"] {
|
||||||
|
parseMapEntry(r, entry, tag)
|
||||||
|
}
|
||||||
|
} else { // this element is itself an entry
|
||||||
|
parseMapEntry(r, node, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseMapEntry deserializes a map entry from a XML node.
|
||||||
|
func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||||
|
kname, vname := "key", "value"
|
||||||
|
if n := tag.Get("locationNameKey"); n != "" {
|
||||||
|
kname = n
|
||||||
|
}
|
||||||
|
if n := tag.Get("locationNameValue"); n != "" {
|
||||||
|
vname = n
|
||||||
|
}
|
||||||
|
|
||||||
|
keys, ok := node.Children[kname]
|
||||||
|
values := node.Children[vname]
|
||||||
|
if ok {
|
||||||
|
for i, key := range keys {
|
||||||
|
keyR := reflect.ValueOf(key.Text)
|
||||||
|
value := values[i]
|
||||||
|
valueR := reflect.New(r.Type().Elem()).Elem()
|
||||||
|
|
||||||
|
parse(valueR, value, "")
|
||||||
|
r.SetMapIndex(keyR, valueR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseScaller deserializes an XMLNode value into a concrete type based on the
|
||||||
|
// interface type of r.
|
||||||
|
//
|
||||||
|
// Error is returned if the deserialization fails due to invalid type conversion,
|
||||||
|
// or unsupported interface type.
|
||||||
|
func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||||
|
switch r.Interface().(type) {
|
||||||
|
case *string:
|
||||||
|
r.Set(reflect.ValueOf(&node.Text))
|
||||||
|
return nil
|
||||||
|
case []byte:
|
||||||
|
b, err := base64.StdEncoding.DecodeString(node.Text)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Set(reflect.ValueOf(b))
|
||||||
|
case *bool:
|
||||||
|
v, err := strconv.ParseBool(node.Text)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Set(reflect.ValueOf(&v))
|
||||||
|
case *int64:
|
||||||
|
v, err := strconv.ParseInt(node.Text, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Set(reflect.ValueOf(&v))
|
||||||
|
case *float64:
|
||||||
|
v, err := strconv.ParseFloat(node.Text, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Set(reflect.ValueOf(&v))
|
||||||
|
case *time.Time:
|
||||||
|
const ISO8601UTC = "2006-01-02T15:04:05Z"
|
||||||
|
t, err := time.Parse(ISO8601UTC, node.Text)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Set(reflect.ValueOf(&t))
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
142
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go
generated
vendored
Normal file
142
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go
generated
vendored
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
package xmlutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A XMLNode contains the values to be encoded or decoded.
|
||||||
|
type XMLNode struct {
|
||||||
|
Name xml.Name `json:",omitempty"`
|
||||||
|
Children map[string][]*XMLNode `json:",omitempty"`
|
||||||
|
Text string `json:",omitempty"`
|
||||||
|
Attr []xml.Attr `json:",omitempty"`
|
||||||
|
|
||||||
|
namespaces map[string]string
|
||||||
|
parent *XMLNode
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewXMLElement returns a pointer to a new XMLNode initialized to default values.
|
||||||
|
func NewXMLElement(name xml.Name) *XMLNode {
|
||||||
|
return &XMLNode{
|
||||||
|
Name: name,
|
||||||
|
Children: map[string][]*XMLNode{},
|
||||||
|
Attr: []xml.Attr{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddChild adds child to the XMLNode.
|
||||||
|
func (n *XMLNode) AddChild(child *XMLNode) {
|
||||||
|
if _, ok := n.Children[child.Name.Local]; !ok {
|
||||||
|
n.Children[child.Name.Local] = []*XMLNode{}
|
||||||
|
}
|
||||||
|
n.Children[child.Name.Local] = append(n.Children[child.Name.Local], child)
|
||||||
|
}
|
||||||
|
|
||||||
|
// XMLToStruct converts a xml.Decoder stream to XMLNode with nested values.
|
||||||
|
func XMLToStruct(d *xml.Decoder, s *xml.StartElement) (*XMLNode, error) {
|
||||||
|
out := &XMLNode{}
|
||||||
|
for {
|
||||||
|
tok, err := d.Token()
|
||||||
|
if tok == nil || err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typed := tok.(type) {
|
||||||
|
case xml.CharData:
|
||||||
|
out.Text = string(typed.Copy())
|
||||||
|
case xml.StartElement:
|
||||||
|
el := typed.Copy()
|
||||||
|
out.Attr = el.Attr
|
||||||
|
if out.Children == nil {
|
||||||
|
out.Children = map[string][]*XMLNode{}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := typed.Name.Local
|
||||||
|
slice := out.Children[name]
|
||||||
|
if slice == nil {
|
||||||
|
slice = []*XMLNode{}
|
||||||
|
}
|
||||||
|
node, e := XMLToStruct(d, &el)
|
||||||
|
out.findNamespaces()
|
||||||
|
if e != nil {
|
||||||
|
return out, e
|
||||||
|
}
|
||||||
|
node.Name = typed.Name
|
||||||
|
node.findNamespaces()
|
||||||
|
tempOut := *out
|
||||||
|
// Save into a temp variable, simply because out gets squashed during
|
||||||
|
// loop iterations
|
||||||
|
node.parent = &tempOut
|
||||||
|
slice = append(slice, node)
|
||||||
|
out.Children[name] = slice
|
||||||
|
case xml.EndElement:
|
||||||
|
if s != nil && s.Name.Local == typed.Name.Local { // matching end token
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
out = &XMLNode{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *XMLNode) findNamespaces() {
|
||||||
|
ns := map[string]string{}
|
||||||
|
for _, a := range n.Attr {
|
||||||
|
if a.Name.Space == "xmlns" {
|
||||||
|
ns[a.Value] = a.Name.Local
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n.namespaces = ns
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *XMLNode) findElem(name string) (string, bool) {
|
||||||
|
for node := n; node != nil; node = node.parent {
|
||||||
|
for _, a := range node.Attr {
|
||||||
|
namespace := a.Name.Space
|
||||||
|
if v, ok := node.namespaces[namespace]; ok {
|
||||||
|
namespace = v
|
||||||
|
}
|
||||||
|
if name == fmt.Sprintf("%s:%s", namespace, a.Name.Local) {
|
||||||
|
return a.Value, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructToXML writes an XMLNode to a xml.Encoder as tokens.
|
||||||
|
func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error {
|
||||||
|
e.EncodeToken(xml.StartElement{Name: node.Name, Attr: node.Attr})
|
||||||
|
|
||||||
|
if node.Text != "" {
|
||||||
|
e.EncodeToken(xml.CharData([]byte(node.Text)))
|
||||||
|
} else if sorted {
|
||||||
|
sortedNames := []string{}
|
||||||
|
for k := range node.Children {
|
||||||
|
sortedNames = append(sortedNames, k)
|
||||||
|
}
|
||||||
|
sort.Strings(sortedNames)
|
||||||
|
|
||||||
|
for _, k := range sortedNames {
|
||||||
|
for _, v := range node.Children[k] {
|
||||||
|
StructToXML(e, v, sorted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, c := range node.Children {
|
||||||
|
for _, v := range c {
|
||||||
|
StructToXML(e, v, sorted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.EncodeToken(xml.EndElement{Name: node.Name})
|
||||||
|
return e.Flush()
|
||||||
|
}
|
134
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/waiter/waiter.go
generated
vendored
Normal file
134
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/private/waiter/waiter.go
generated
vendored
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
package waiter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Config provides a collection of configuration values to setup a generated
|
||||||
|
// waiter code with.
|
||||||
|
type Config struct {
|
||||||
|
Name string
|
||||||
|
Delay int
|
||||||
|
MaxAttempts int
|
||||||
|
Operation string
|
||||||
|
Acceptors []WaitAcceptor
|
||||||
|
}
|
||||||
|
|
||||||
|
// A WaitAcceptor provides the information needed to wait for an API operation
|
||||||
|
// to complete.
|
||||||
|
type WaitAcceptor struct {
|
||||||
|
Expected interface{}
|
||||||
|
Matcher string
|
||||||
|
State string
|
||||||
|
Argument string
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Waiter provides waiting for an operation to complete.
|
||||||
|
type Waiter struct {
|
||||||
|
Config
|
||||||
|
Client interface{}
|
||||||
|
Input interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait waits for an operation to complete, expire max attempts, or fail. Error
|
||||||
|
// is returned if the operation fails.
|
||||||
|
func (w *Waiter) Wait() error {
|
||||||
|
client := reflect.ValueOf(w.Client)
|
||||||
|
in := reflect.ValueOf(w.Input)
|
||||||
|
method := client.MethodByName(w.Config.Operation + "Request")
|
||||||
|
|
||||||
|
for i := 0; i < w.MaxAttempts; i++ {
|
||||||
|
res := method.Call([]reflect.Value{in})
|
||||||
|
req := res[0].Interface().(*request.Request)
|
||||||
|
req.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Waiter"))
|
||||||
|
|
||||||
|
err := req.Send()
|
||||||
|
for _, a := range w.Acceptors {
|
||||||
|
result := false
|
||||||
|
var vals []interface{}
|
||||||
|
switch a.Matcher {
|
||||||
|
case "pathAll", "path":
|
||||||
|
// 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 "pathAny":
|
||||||
|
// 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 "status":
|
||||||
|
s := a.Expected.(int)
|
||||||
|
result = s == req.HTTPResponse.StatusCode
|
||||||
|
case "error":
|
||||||
|
if aerr, ok := err.(awserr.Error); ok {
|
||||||
|
result = aerr.Code() == a.Expected.(string)
|
||||||
|
}
|
||||||
|
case "pathList":
|
||||||
|
// ignored matcher
|
||||||
|
default:
|
||||||
|
logf(client, "WARNING: Waiter for %s encountered unexpected matcher: %s",
|
||||||
|
w.Config.Operation, a.Matcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !result {
|
||||||
|
// If there was no matching result found there is nothing more to do
|
||||||
|
// for this response, retry the request.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch a.State {
|
||||||
|
case "success":
|
||||||
|
// waiter completed
|
||||||
|
return nil
|
||||||
|
case "failure":
|
||||||
|
// Waiter failure state triggered
|
||||||
|
return awserr.New("ResourceNotReady",
|
||||||
|
fmt.Sprintf("failed waiting for successful resource state"), err)
|
||||||
|
case "retry":
|
||||||
|
// clear the error and retry the operation
|
||||||
|
err = nil
|
||||||
|
default:
|
||||||
|
logf(client, "WARNING: Waiter for %s encountered unexpected state: %s",
|
||||||
|
w.Config.Operation, a.State)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second * time.Duration(w.Delay))
|
||||||
|
}
|
||||||
|
|
||||||
|
return awserr.New("ResourceNotReady",
|
||||||
|
fmt.Sprintf("exceeded %d wait attempts", w.MaxAttempts), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func logf(client reflect.Value, msg string, args ...interface{}) {
|
||||||
|
cfgVal := client.FieldByName("Config")
|
||||||
|
if !cfgVal.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cfg, ok := cfgVal.Interface().(*aws.Config); ok && cfg.Logger != nil {
|
||||||
|
cfg.Logger.Log(fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
}
|
54119
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/ec2/api.go
generated
vendored
Normal file
54119
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/ec2/api.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
67
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/ec2/customizations.go
generated
vendored
Normal file
67
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/ec2/customizations.go
generated
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
package ec2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initRequest = func(r *request.Request) {
|
||||||
|
if r.Operation.Name == opCopySnapshot { // fill the PresignedURL parameter
|
||||||
|
r.Handlers.Build.PushFront(fillPresignedURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillPresignedURL(r *request.Request) {
|
||||||
|
if !r.ParamsFilled() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
origParams := r.Params.(*CopySnapshotInput)
|
||||||
|
|
||||||
|
// Stop if PresignedURL/DestinationRegion is set
|
||||||
|
if origParams.PresignedUrl != nil || origParams.DestinationRegion != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
origParams.DestinationRegion = r.Config.Region
|
||||||
|
newParams := awsutil.CopyOf(r.Params).(*CopySnapshotInput)
|
||||||
|
|
||||||
|
// Create a new request based on the existing request. We will use this to
|
||||||
|
// presign the CopySnapshot request against the source region.
|
||||||
|
cfg := r.Config.Copy(aws.NewConfig().
|
||||||
|
WithEndpoint("").
|
||||||
|
WithRegion(aws.StringValue(origParams.SourceRegion)))
|
||||||
|
|
||||||
|
clientInfo := r.ClientInfo
|
||||||
|
resolved, err := r.Config.EndpointResolver.EndpointFor(
|
||||||
|
clientInfo.ServiceName, aws.StringValue(cfg.Region),
|
||||||
|
func(opt *endpoints.Options) {
|
||||||
|
opt.DisableSSL = aws.BoolValue(cfg.DisableSSL)
|
||||||
|
opt.UseDualStack = aws.BoolValue(cfg.UseDualStack)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clientInfo.Endpoint = resolved.URL
|
||||||
|
clientInfo.SigningRegion = resolved.SigningRegion
|
||||||
|
|
||||||
|
// Presign a CopySnapshot request with modified params
|
||||||
|
req := request.New(*cfg, clientInfo, r.Handlers, r.Retryer, r.Operation, newParams, r.Data)
|
||||||
|
url, err := req.Presign(5 * time.Minute) // 5 minutes should be enough.
|
||||||
|
if err != nil { // bubble error back up to original request
|
||||||
|
r.Error = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have our URL, set it on params
|
||||||
|
origParams.PresignedUrl = &url
|
||||||
|
}
|
3
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/ec2/errors.go
generated
vendored
Normal file
3
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/ec2/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||||
|
|
||||||
|
package ec2
|
94
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/ec2/service.go
generated
vendored
Normal file
94
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/ec2/service.go
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||||
|
|
||||||
|
package ec2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/client"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol/ec2query"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Amazon Elastic Compute Cloud (Amazon EC2) provides resizable computing capacity
|
||||||
|
// in the Amazon Web Services (AWS) cloud. Using Amazon EC2 eliminates your
|
||||||
|
// need to invest in hardware up front, so you can develop and deploy applications
|
||||||
|
// faster.
|
||||||
|
// The service client's operations are safe to be used concurrently.
|
||||||
|
// It is not safe to mutate any of the client's properties though.
|
||||||
|
// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15
|
||||||
|
type EC2 struct {
|
||||||
|
*client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for custom client initialization logic
|
||||||
|
var initClient func(*client.Client)
|
||||||
|
|
||||||
|
// Used for custom request initialization logic
|
||||||
|
var initRequest func(*request.Request)
|
||||||
|
|
||||||
|
// Service information constants
|
||||||
|
const (
|
||||||
|
ServiceName = "ec2" // Service endpoint prefix API calls made to.
|
||||||
|
EndpointsID = ServiceName // Service ID for Regions and Endpoints metadata.
|
||||||
|
)
|
||||||
|
|
||||||
|
// New creates a new instance of the EC2 client with a session.
|
||||||
|
// If additional configuration is needed for the client instance use the optional
|
||||||
|
// aws.Config parameter to add your extra config.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// // Create a EC2 client from just a session.
|
||||||
|
// svc := ec2.New(mySession)
|
||||||
|
//
|
||||||
|
// // Create a EC2 client with additional configuration
|
||||||
|
// svc := ec2.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||||
|
func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2 {
|
||||||
|
c := p.ClientConfig(EndpointsID, cfgs...)
|
||||||
|
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newClient creates, initializes and returns a new service client instance.
|
||||||
|
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *EC2 {
|
||||||
|
svc := &EC2{
|
||||||
|
Client: client.New(
|
||||||
|
cfg,
|
||||||
|
metadata.ClientInfo{
|
||||||
|
ServiceName: ServiceName,
|
||||||
|
SigningName: signingName,
|
||||||
|
SigningRegion: signingRegion,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
APIVersion: "2016-11-15",
|
||||||
|
},
|
||||||
|
handlers,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
|
||||||
|
svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler)
|
||||||
|
svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler)
|
||||||
|
svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler)
|
||||||
|
svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler)
|
||||||
|
|
||||||
|
// Run custom client initialization if present
|
||||||
|
if initClient != nil {
|
||||||
|
initClient(svc.Client)
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc
|
||||||
|
}
|
||||||
|
|
||||||
|
// newRequest creates a new request for a EC2 operation and runs any
|
||||||
|
// custom request initialization.
|
||||||
|
func (c *EC2) newRequest(op *request.Operation, params, data interface{}) *request.Request {
|
||||||
|
req := c.NewRequest(op, params, data)
|
||||||
|
|
||||||
|
// Run custom request initialization if present
|
||||||
|
if initRequest != nil {
|
||||||
|
initRequest(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return req
|
||||||
|
}
|
1060
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/ec2/waiters.go
generated
vendored
Normal file
1060
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/ec2/waiters.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2260
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/sts/api.go
generated
vendored
Normal file
2260
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/sts/api.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
12
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/sts/customizations.go
generated
vendored
Normal file
12
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/sts/customizations.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package sts
|
||||||
|
|
||||||
|
import "github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initRequest = func(r *request.Request) {
|
||||||
|
switch r.Operation.Name {
|
||||||
|
case opAssumeRoleWithSAML, opAssumeRoleWithWebIdentity:
|
||||||
|
r.Handlers.Sign.Clear() // these operations are unsigned
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/sts/errors.go
generated
vendored
Normal file
73
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/sts/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||||
|
|
||||||
|
package sts
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// ErrCodeExpiredTokenException for service response error code
|
||||||
|
// "ExpiredTokenException".
|
||||||
|
//
|
||||||
|
// The web identity token that was passed is expired or is not valid. Get a
|
||||||
|
// new identity token from the identity provider and then retry the request.
|
||||||
|
ErrCodeExpiredTokenException = "ExpiredTokenException"
|
||||||
|
|
||||||
|
// ErrCodeIDPCommunicationErrorException for service response error code
|
||||||
|
// "IDPCommunicationError".
|
||||||
|
//
|
||||||
|
// The request could not be fulfilled because the non-AWS identity provider
|
||||||
|
// (IDP) that was asked to verify the incoming identity token could not be reached.
|
||||||
|
// This is often a transient error caused by network conditions. Retry the request
|
||||||
|
// a limited number of times so that you don't exceed the request rate. If the
|
||||||
|
// error persists, the non-AWS identity provider might be down or not responding.
|
||||||
|
ErrCodeIDPCommunicationErrorException = "IDPCommunicationError"
|
||||||
|
|
||||||
|
// ErrCodeIDPRejectedClaimException for service response error code
|
||||||
|
// "IDPRejectedClaim".
|
||||||
|
//
|
||||||
|
// The identity provider (IdP) reported that authentication failed. This might
|
||||||
|
// be because the claim is invalid.
|
||||||
|
//
|
||||||
|
// If this error is returned for the AssumeRoleWithWebIdentity operation, it
|
||||||
|
// can also mean that the claim has expired or has been explicitly revoked.
|
||||||
|
ErrCodeIDPRejectedClaimException = "IDPRejectedClaim"
|
||||||
|
|
||||||
|
// ErrCodeInvalidAuthorizationMessageException for service response error code
|
||||||
|
// "InvalidAuthorizationMessageException".
|
||||||
|
//
|
||||||
|
// The error returned if the message passed to DecodeAuthorizationMessage was
|
||||||
|
// invalid. This can happen if the token contains invalid characters, such as
|
||||||
|
// linebreaks.
|
||||||
|
ErrCodeInvalidAuthorizationMessageException = "InvalidAuthorizationMessageException"
|
||||||
|
|
||||||
|
// ErrCodeInvalidIdentityTokenException for service response error code
|
||||||
|
// "InvalidIdentityToken".
|
||||||
|
//
|
||||||
|
// The web identity token that was passed could not be validated by AWS. Get
|
||||||
|
// a new identity token from the identity provider and then retry the request.
|
||||||
|
ErrCodeInvalidIdentityTokenException = "InvalidIdentityToken"
|
||||||
|
|
||||||
|
// ErrCodeMalformedPolicyDocumentException for service response error code
|
||||||
|
// "MalformedPolicyDocument".
|
||||||
|
//
|
||||||
|
// The request was rejected because the policy document was malformed. The error
|
||||||
|
// message describes the specific error.
|
||||||
|
ErrCodeMalformedPolicyDocumentException = "MalformedPolicyDocument"
|
||||||
|
|
||||||
|
// ErrCodePackedPolicyTooLargeException for service response error code
|
||||||
|
// "PackedPolicyTooLarge".
|
||||||
|
//
|
||||||
|
// The request was rejected because the policy document was too large. The error
|
||||||
|
// message describes how big the policy document is, in packed form, as a percentage
|
||||||
|
// of what the API allows.
|
||||||
|
ErrCodePackedPolicyTooLargeException = "PackedPolicyTooLarge"
|
||||||
|
|
||||||
|
// ErrCodeRegionDisabledException for service response error code
|
||||||
|
// "RegionDisabledException".
|
||||||
|
//
|
||||||
|
// STS is not activated in the requested region for the account that is being
|
||||||
|
// asked to generate credentials. The account administrator must use the IAM
|
||||||
|
// console to activate STS in that region. For more information, see Activating
|
||||||
|
// and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
ErrCodeRegionDisabledException = "RegionDisabledException"
|
||||||
|
)
|
135
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/sts/service.go
generated
vendored
Normal file
135
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/aws/aws-sdk-go/service/sts/service.go
generated
vendored
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||||
|
|
||||||
|
package sts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/client"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The AWS Security Token Service (STS) is a web service that enables you to
|
||||||
|
// request temporary, limited-privilege credentials for AWS Identity and Access
|
||||||
|
// Management (IAM) users or for users that you authenticate (federated users).
|
||||||
|
// This guide provides descriptions of the STS API. For more detailed information
|
||||||
|
// about using this service, go to Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html).
|
||||||
|
//
|
||||||
|
// As an alternative to using the API, you can use one of the AWS SDKs, which
|
||||||
|
// consist of libraries and sample code for various programming languages and
|
||||||
|
// platforms (Java, Ruby, .NET, iOS, Android, etc.). The SDKs provide a convenient
|
||||||
|
// way to create programmatic access to STS. For example, the SDKs take care
|
||||||
|
// of cryptographically signing requests, managing errors, and retrying requests
|
||||||
|
// automatically. For information about the AWS SDKs, including how to download
|
||||||
|
// and install them, see the Tools for Amazon Web Services page (http://aws.amazon.com/tools/).
|
||||||
|
//
|
||||||
|
// For information about setting up signatures and authorization through the
|
||||||
|
// API, go to Signing AWS API Requests (http://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html)
|
||||||
|
// in the AWS General Reference. For general information about the Query API,
|
||||||
|
// go to Making Query Requests (http://docs.aws.amazon.com/IAM/latest/UserGuide/IAM_UsingQueryAPI.html)
|
||||||
|
// in Using IAM. For information about using security tokens with other AWS
|
||||||
|
// products, go to AWS Services That Work with IAM (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// If you're new to AWS and need additional technical information about a specific
|
||||||
|
// AWS product, you can find the product's technical documentation at http://aws.amazon.com/documentation/
|
||||||
|
// (http://aws.amazon.com/documentation/).
|
||||||
|
//
|
||||||
|
// Endpoints
|
||||||
|
//
|
||||||
|
// The AWS Security Token Service (STS) has a default endpoint of https://sts.amazonaws.com
|
||||||
|
// that maps to the US East (N. Virginia) region. Additional regions are available
|
||||||
|
// and are activated by default. For more information, see Activating and Deactivating
|
||||||
|
// AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// For information about STS endpoints, see Regions and Endpoints (http://docs.aws.amazon.com/general/latest/gr/rande.html#sts_region)
|
||||||
|
// in the AWS General Reference.
|
||||||
|
//
|
||||||
|
// Recording API requests
|
||||||
|
//
|
||||||
|
// STS supports AWS CloudTrail, which is a service that records AWS calls for
|
||||||
|
// your AWS account and delivers log files to an Amazon S3 bucket. By using
|
||||||
|
// information collected by CloudTrail, you can determine what requests were
|
||||||
|
// successfully made to STS, who made the request, when it was made, and so
|
||||||
|
// on. To learn more about CloudTrail, including how to turn it on and find
|
||||||
|
// your log files, see the AWS CloudTrail User Guide (http://docs.aws.amazon.com/awscloudtrail/latest/userguide/what_is_cloud_trail_top_level.html).
|
||||||
|
// The service client's operations are safe to be used concurrently.
|
||||||
|
// It is not safe to mutate any of the client's properties though.
|
||||||
|
// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15
|
||||||
|
type STS struct {
|
||||||
|
*client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for custom client initialization logic
|
||||||
|
var initClient func(*client.Client)
|
||||||
|
|
||||||
|
// Used for custom request initialization logic
|
||||||
|
var initRequest func(*request.Request)
|
||||||
|
|
||||||
|
// Service information constants
|
||||||
|
const (
|
||||||
|
ServiceName = "sts" // Service endpoint prefix API calls made to.
|
||||||
|
EndpointsID = ServiceName // Service ID for Regions and Endpoints metadata.
|
||||||
|
)
|
||||||
|
|
||||||
|
// New creates a new instance of the STS client with a session.
|
||||||
|
// If additional configuration is needed for the client instance use the optional
|
||||||
|
// aws.Config parameter to add your extra config.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// // Create a STS client from just a session.
|
||||||
|
// svc := sts.New(mySession)
|
||||||
|
//
|
||||||
|
// // Create a STS client with additional configuration
|
||||||
|
// svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||||
|
func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS {
|
||||||
|
c := p.ClientConfig(EndpointsID, cfgs...)
|
||||||
|
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newClient creates, initializes and returns a new service client instance.
|
||||||
|
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *STS {
|
||||||
|
svc := &STS{
|
||||||
|
Client: client.New(
|
||||||
|
cfg,
|
||||||
|
metadata.ClientInfo{
|
||||||
|
ServiceName: ServiceName,
|
||||||
|
SigningName: signingName,
|
||||||
|
SigningRegion: signingRegion,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
APIVersion: "2011-06-15",
|
||||||
|
},
|
||||||
|
handlers,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
|
||||||
|
svc.Handlers.Build.PushBackNamed(query.BuildHandler)
|
||||||
|
svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler)
|
||||||
|
svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler)
|
||||||
|
svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler)
|
||||||
|
|
||||||
|
// Run custom client initialization if present
|
||||||
|
if initClient != nil {
|
||||||
|
initClient(svc.Client)
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc
|
||||||
|
}
|
||||||
|
|
||||||
|
// newRequest creates a new request for a STS operation and runs any
|
||||||
|
// custom request initialization.
|
||||||
|
func (c *STS) newRequest(op *request.Operation, params, data interface{}) *request.Request {
|
||||||
|
req := c.NewRequest(op, params, data)
|
||||||
|
|
||||||
|
// Run custom request initialization if present
|
||||||
|
if initRequest != nil {
|
||||||
|
initRequest(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return req
|
||||||
|
}
|
191
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/LICENSE
generated
vendored
Normal file
191
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
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:
|
||||||
|
|
||||||
|
You must give any other recipients of the Work or Derivative Works a copy of
|
||||||
|
this License; and
|
||||||
|
You must cause any modified files to carry prominent notices stating that You
|
||||||
|
changed the files; and
|
||||||
|
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
|
||||||
|
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.
|
12
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/Makefile
generated
vendored
Normal file
12
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
.PHONY: build test bench vet
|
||||||
|
|
||||||
|
build: vet bench
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test -v -cover -race
|
||||||
|
|
||||||
|
bench:
|
||||||
|
go test -v -cover -race -test.bench=. -test.benchmem
|
||||||
|
|
||||||
|
vet:
|
||||||
|
go vet
|
703
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/README.md
generated
vendored
Normal file
703
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/README.md
generated
vendored
Normal file
|
@ -0,0 +1,703 @@
|
||||||
|
INI [![Build Status](https://travis-ci.org/go-ini/ini.svg?branch=master)](https://travis-ci.org/go-ini/ini)
|
||||||
|
===
|
||||||
|
|
||||||
|
![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200)
|
||||||
|
|
||||||
|
Package ini provides INI file read and write functionality in Go.
|
||||||
|
|
||||||
|
[简体中文](README_ZH.md)
|
||||||
|
|
||||||
|
## Feature
|
||||||
|
|
||||||
|
- Load multiple data sources(`[]byte` or file) with overwrites.
|
||||||
|
- Read with recursion values.
|
||||||
|
- Read with parent-child sections.
|
||||||
|
- Read with auto-increment key names.
|
||||||
|
- Read with multiple-line values.
|
||||||
|
- Read with tons of helper methods.
|
||||||
|
- Read and convert values to Go types.
|
||||||
|
- Read and **WRITE** comments of sections and keys.
|
||||||
|
- Manipulate sections, keys and comments with ease.
|
||||||
|
- Keep sections and keys in order as you parse and save.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To use a tagged revision:
|
||||||
|
|
||||||
|
go get gopkg.in/ini.v1
|
||||||
|
|
||||||
|
To use with latest changes:
|
||||||
|
|
||||||
|
go get github.com/go-ini/ini
|
||||||
|
|
||||||
|
Please add `-u` flag to update in the future.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
If you want to test on your machine, please apply `-t` flag:
|
||||||
|
|
||||||
|
go get -t gopkg.in/ini.v1
|
||||||
|
|
||||||
|
Please add `-u` flag to update in the future.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Loading from data sources
|
||||||
|
|
||||||
|
A **Data Source** is either raw data in type `[]byte` or a file name with type `string` and you can load **as many data sources as you want**. Passing other types will simply return an error.
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg, err := ini.Load([]byte("raw data"), "filename")
|
||||||
|
```
|
||||||
|
|
||||||
|
Or start with an empty object:
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg := ini.Empty()
|
||||||
|
```
|
||||||
|
|
||||||
|
When you cannot decide how many data sources to load at the beginning, you will still be able to **Append()** them later.
|
||||||
|
|
||||||
|
```go
|
||||||
|
err := cfg.Append("other file", []byte("other raw data"))
|
||||||
|
```
|
||||||
|
|
||||||
|
If you have a list of files with possibilities that some of them may not available at the time, and you don't know exactly which ones, you can use `LooseLoad` to ignore nonexistent files without returning error.
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg, err := ini.LooseLoad("filename", "filename_404")
|
||||||
|
```
|
||||||
|
|
||||||
|
The cool thing is, whenever the file is available to load while you're calling `Reload` method, it will be counted as usual.
|
||||||
|
|
||||||
|
#### Ignore cases of key name
|
||||||
|
|
||||||
|
When you do not care about cases of section and key names, you can use `InsensitiveLoad` to force all names to be lowercased while parsing.
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg, err := ini.InsensitiveLoad("filename")
|
||||||
|
//...
|
||||||
|
|
||||||
|
// sec1 and sec2 are the exactly same section object
|
||||||
|
sec1, err := cfg.GetSection("Section")
|
||||||
|
sec2, err := cfg.GetSection("SecTIOn")
|
||||||
|
|
||||||
|
// key1 and key2 are the exactly same key object
|
||||||
|
key1, err := cfg.GetKey("Key")
|
||||||
|
key2, err := cfg.GetKey("KeY")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### MySQL-like boolean key
|
||||||
|
|
||||||
|
MySQL's configuration allows a key without value as follows:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[mysqld]
|
||||||
|
...
|
||||||
|
skip-host-cache
|
||||||
|
skip-name-resolve
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, this is considered as missing value. But if you know you're going to deal with those cases, you can assign advanced load options:
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
|
||||||
|
```
|
||||||
|
|
||||||
|
The value of those keys are always `true`, and when you save to a file, it will keep in the same foramt as you read.
|
||||||
|
|
||||||
|
### Working with sections
|
||||||
|
|
||||||
|
To get a section, you would need to:
|
||||||
|
|
||||||
|
```go
|
||||||
|
section, err := cfg.GetSection("section name")
|
||||||
|
```
|
||||||
|
|
||||||
|
For a shortcut for default section, just give an empty string as name:
|
||||||
|
|
||||||
|
```go
|
||||||
|
section, err := cfg.GetSection("")
|
||||||
|
```
|
||||||
|
|
||||||
|
When you're pretty sure the section exists, following code could make your life easier:
|
||||||
|
|
||||||
|
```go
|
||||||
|
section := cfg.Section("")
|
||||||
|
```
|
||||||
|
|
||||||
|
What happens when the section somehow does not exist? Don't panic, it automatically creates and returns a new section to you.
|
||||||
|
|
||||||
|
To create a new section:
|
||||||
|
|
||||||
|
```go
|
||||||
|
err := cfg.NewSection("new section")
|
||||||
|
```
|
||||||
|
|
||||||
|
To get a list of sections or section names:
|
||||||
|
|
||||||
|
```go
|
||||||
|
sections := cfg.Sections()
|
||||||
|
names := cfg.SectionStrings()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Working with keys
|
||||||
|
|
||||||
|
To get a key under a section:
|
||||||
|
|
||||||
|
```go
|
||||||
|
key, err := cfg.Section("").GetKey("key name")
|
||||||
|
```
|
||||||
|
|
||||||
|
Same rule applies to key operations:
|
||||||
|
|
||||||
|
```go
|
||||||
|
key := cfg.Section("").Key("key name")
|
||||||
|
```
|
||||||
|
|
||||||
|
To check if a key exists:
|
||||||
|
|
||||||
|
```go
|
||||||
|
yes := cfg.Section("").HasKey("key name")
|
||||||
|
```
|
||||||
|
|
||||||
|
To create a new key:
|
||||||
|
|
||||||
|
```go
|
||||||
|
err := cfg.Section("").NewKey("name", "value")
|
||||||
|
```
|
||||||
|
|
||||||
|
To get a list of keys or key names:
|
||||||
|
|
||||||
|
```go
|
||||||
|
keys := cfg.Section("").Keys()
|
||||||
|
names := cfg.Section("").KeyStrings()
|
||||||
|
```
|
||||||
|
|
||||||
|
To get a clone hash of keys and corresponding values:
|
||||||
|
|
||||||
|
```go
|
||||||
|
hash := cfg.Section("").KeysHash()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Working with values
|
||||||
|
|
||||||
|
To get a string value:
|
||||||
|
|
||||||
|
```go
|
||||||
|
val := cfg.Section("").Key("key name").String()
|
||||||
|
```
|
||||||
|
|
||||||
|
To validate key value on the fly:
|
||||||
|
|
||||||
|
```go
|
||||||
|
val := cfg.Section("").Key("key name").Validate(func(in string) string {
|
||||||
|
if len(in) == 0 {
|
||||||
|
return "default"
|
||||||
|
}
|
||||||
|
return in
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
If you do not want any auto-transformation (such as recursive read) for the values, you can get raw value directly (this way you get much better performance):
|
||||||
|
|
||||||
|
```go
|
||||||
|
val := cfg.Section("").Key("key name").Value()
|
||||||
|
```
|
||||||
|
|
||||||
|
To check if raw value exists:
|
||||||
|
|
||||||
|
```go
|
||||||
|
yes := cfg.Section("").HasValue("test value")
|
||||||
|
```
|
||||||
|
|
||||||
|
To get value with types:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// For boolean values:
|
||||||
|
// true when value is: 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On
|
||||||
|
// false when value is: 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off
|
||||||
|
v, err = cfg.Section("").Key("BOOL").Bool()
|
||||||
|
v, err = cfg.Section("").Key("FLOAT64").Float64()
|
||||||
|
v, err = cfg.Section("").Key("INT").Int()
|
||||||
|
v, err = cfg.Section("").Key("INT64").Int64()
|
||||||
|
v, err = cfg.Section("").Key("UINT").Uint()
|
||||||
|
v, err = cfg.Section("").Key("UINT64").Uint64()
|
||||||
|
v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339)
|
||||||
|
v, err = cfg.Section("").Key("TIME").Time() // RFC3339
|
||||||
|
|
||||||
|
v = cfg.Section("").Key("BOOL").MustBool()
|
||||||
|
v = cfg.Section("").Key("FLOAT64").MustFloat64()
|
||||||
|
v = cfg.Section("").Key("INT").MustInt()
|
||||||
|
v = cfg.Section("").Key("INT64").MustInt64()
|
||||||
|
v = cfg.Section("").Key("UINT").MustUint()
|
||||||
|
v = cfg.Section("").Key("UINT64").MustUint64()
|
||||||
|
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339)
|
||||||
|
v = cfg.Section("").Key("TIME").MustTime() // RFC3339
|
||||||
|
|
||||||
|
// Methods start with Must also accept one argument for default value
|
||||||
|
// when key not found or fail to parse value to given type.
|
||||||
|
// Except method MustString, which you have to pass a default value.
|
||||||
|
|
||||||
|
v = cfg.Section("").Key("String").MustString("default")
|
||||||
|
v = cfg.Section("").Key("BOOL").MustBool(true)
|
||||||
|
v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25)
|
||||||
|
v = cfg.Section("").Key("INT").MustInt(10)
|
||||||
|
v = cfg.Section("").Key("INT64").MustInt64(99)
|
||||||
|
v = cfg.Section("").Key("UINT").MustUint(3)
|
||||||
|
v = cfg.Section("").Key("UINT64").MustUint64(6)
|
||||||
|
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now())
|
||||||
|
v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339
|
||||||
|
```
|
||||||
|
|
||||||
|
What if my value is three-line long?
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[advance]
|
||||||
|
ADDRESS = """404 road,
|
||||||
|
NotFound, State, 5000
|
||||||
|
Earth"""
|
||||||
|
```
|
||||||
|
|
||||||
|
Not a problem!
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("advance").Key("ADDRESS").String()
|
||||||
|
|
||||||
|
/* --- start ---
|
||||||
|
404 road,
|
||||||
|
NotFound, State, 5000
|
||||||
|
Earth
|
||||||
|
------ end --- */
|
||||||
|
```
|
||||||
|
|
||||||
|
That's cool, how about continuation lines?
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[advance]
|
||||||
|
two_lines = how about \
|
||||||
|
continuation lines?
|
||||||
|
lots_of_lines = 1 \
|
||||||
|
2 \
|
||||||
|
3 \
|
||||||
|
4
|
||||||
|
```
|
||||||
|
|
||||||
|
Piece of cake!
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("advance").Key("two_lines").String() // how about continuation lines?
|
||||||
|
cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4
|
||||||
|
```
|
||||||
|
|
||||||
|
Well, I hate continuation lines, how do I disable that?
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg, err := ini.LoadSources(ini.LoadOptions{
|
||||||
|
IgnoreContinuation: true,
|
||||||
|
}, "filename")
|
||||||
|
```
|
||||||
|
|
||||||
|
Holy crap!
|
||||||
|
|
||||||
|
Note that single quotes around values will be stripped:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
foo = "some value" // foo: some value
|
||||||
|
bar = 'some value' // bar: some value
|
||||||
|
```
|
||||||
|
|
||||||
|
That's all? Hmm, no.
|
||||||
|
|
||||||
|
#### Helper methods of working with values
|
||||||
|
|
||||||
|
To get value with given candidates:
|
||||||
|
|
||||||
|
```go
|
||||||
|
v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"})
|
||||||
|
v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75})
|
||||||
|
v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30})
|
||||||
|
v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30})
|
||||||
|
v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9})
|
||||||
|
v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9})
|
||||||
|
v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3})
|
||||||
|
v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339
|
||||||
|
```
|
||||||
|
|
||||||
|
Default value will be presented if value of key is not in candidates you given, and default value does not need be one of candidates.
|
||||||
|
|
||||||
|
To validate value in a given range:
|
||||||
|
|
||||||
|
```go
|
||||||
|
vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2)
|
||||||
|
vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20)
|
||||||
|
vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20)
|
||||||
|
vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9)
|
||||||
|
vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9)
|
||||||
|
vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime)
|
||||||
|
vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Auto-split values into a slice
|
||||||
|
|
||||||
|
To use zero value of type for invalid inputs:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
|
||||||
|
// Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0]
|
||||||
|
vals = cfg.Section("").Key("STRINGS").Strings(",")
|
||||||
|
vals = cfg.Section("").Key("FLOAT64S").Float64s(",")
|
||||||
|
vals = cfg.Section("").Key("INTS").Ints(",")
|
||||||
|
vals = cfg.Section("").Key("INT64S").Int64s(",")
|
||||||
|
vals = cfg.Section("").Key("UINTS").Uints(",")
|
||||||
|
vals = cfg.Section("").Key("UINT64S").Uint64s(",")
|
||||||
|
vals = cfg.Section("").Key("TIMES").Times(",")
|
||||||
|
```
|
||||||
|
|
||||||
|
To exclude invalid values out of result slice:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
|
||||||
|
// Input: how, 2.2, are, you -> [2.2]
|
||||||
|
vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",")
|
||||||
|
vals = cfg.Section("").Key("INTS").ValidInts(",")
|
||||||
|
vals = cfg.Section("").Key("INT64S").ValidInt64s(",")
|
||||||
|
vals = cfg.Section("").Key("UINTS").ValidUints(",")
|
||||||
|
vals = cfg.Section("").Key("UINT64S").ValidUint64s(",")
|
||||||
|
vals = cfg.Section("").Key("TIMES").ValidTimes(",")
|
||||||
|
```
|
||||||
|
|
||||||
|
Or to return nothing but error when have invalid inputs:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
|
||||||
|
// Input: how, 2.2, are, you -> error
|
||||||
|
vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",")
|
||||||
|
vals = cfg.Section("").Key("INTS").StrictInts(",")
|
||||||
|
vals = cfg.Section("").Key("INT64S").StrictInt64s(",")
|
||||||
|
vals = cfg.Section("").Key("UINTS").StrictUints(",")
|
||||||
|
vals = cfg.Section("").Key("UINT64S").StrictUint64s(",")
|
||||||
|
vals = cfg.Section("").Key("TIMES").StrictTimes(",")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Save your configuration
|
||||||
|
|
||||||
|
Finally, it's time to save your configuration to somewhere.
|
||||||
|
|
||||||
|
A typical way to save configuration is writing it to a file:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// ...
|
||||||
|
err = cfg.SaveTo("my.ini")
|
||||||
|
err = cfg.SaveToIndent("my.ini", "\t")
|
||||||
|
```
|
||||||
|
|
||||||
|
Another way to save is writing to a `io.Writer` interface:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// ...
|
||||||
|
cfg.WriteTo(writer)
|
||||||
|
cfg.WriteToIndent(writer, "\t")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Usage
|
||||||
|
|
||||||
|
### Recursive Values
|
||||||
|
|
||||||
|
For all value of keys, there is a special syntax `%(<name>)s`, where `<name>` is the key name in same section or default section, and `%(<name>)s` will be replaced by corresponding value(empty string if key not found). You can use this syntax at most 99 level of recursions.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
NAME = ini
|
||||||
|
|
||||||
|
[author]
|
||||||
|
NAME = Unknwon
|
||||||
|
GITHUB = https://github.com/%(NAME)s
|
||||||
|
|
||||||
|
[package]
|
||||||
|
FULL_NAME = github.com/go-ini/%(NAME)s
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon
|
||||||
|
cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parent-child Sections
|
||||||
|
|
||||||
|
You can use `.` in section name to indicate parent-child relationship between two or more sections. If the key not found in the child section, library will try again on its parent section until there is no parent section.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
NAME = ini
|
||||||
|
VERSION = v1
|
||||||
|
IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
|
||||||
|
|
||||||
|
[package]
|
||||||
|
CLONE_URL = https://%(IMPORT_PATH)s
|
||||||
|
|
||||||
|
[package.sub]
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Retrieve parent keys available to a child section
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Auto-increment Key Names
|
||||||
|
|
||||||
|
If key name is `-` in data source, then it would be seen as special syntax for auto-increment key name start from 1, and every section is independent on counter.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[features]
|
||||||
|
-: Support read/write comments of keys and sections
|
||||||
|
-: Support auto-increment of key names
|
||||||
|
-: Support load multiple files to overwrite key values
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Map To Struct
|
||||||
|
|
||||||
|
Want more objective way to play with INI? Cool.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
Name = Unknwon
|
||||||
|
age = 21
|
||||||
|
Male = true
|
||||||
|
Born = 1993-01-01T20:17:05Z
|
||||||
|
|
||||||
|
[Note]
|
||||||
|
Content = Hi is a good man!
|
||||||
|
Cities = HangZhou, Boston
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Note struct {
|
||||||
|
Content string
|
||||||
|
Cities []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
Name string
|
||||||
|
Age int `ini:"age"`
|
||||||
|
Male bool
|
||||||
|
Born time.Time
|
||||||
|
Note
|
||||||
|
Created time.Time `ini:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg, err := ini.Load("path/to/ini")
|
||||||
|
// ...
|
||||||
|
p := new(Person)
|
||||||
|
err = cfg.MapTo(p)
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Things can be simpler.
|
||||||
|
err = ini.MapTo(p, "path/to/ini")
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Just map a section? Fine.
|
||||||
|
n := new(Note)
|
||||||
|
err = cfg.Section("Note").MapTo(n)
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Can I have default value for field? Absolutely.
|
||||||
|
|
||||||
|
Assign it before you map to struct. It will keep the value as it is if the key is not presented or got wrong type.
|
||||||
|
|
||||||
|
```go
|
||||||
|
// ...
|
||||||
|
p := &Person{
|
||||||
|
Name: "Joe",
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
|
||||||
|
It's really cool, but what's the point if you can't give me my file back from struct?
|
||||||
|
|
||||||
|
### Reflect From Struct
|
||||||
|
|
||||||
|
Why not?
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Embeded struct {
|
||||||
|
Dates []time.Time `delim:"|"`
|
||||||
|
Places []string `ini:"places,omitempty"`
|
||||||
|
None []int `ini:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Author struct {
|
||||||
|
Name string `ini:"NAME"`
|
||||||
|
Male bool
|
||||||
|
Age int
|
||||||
|
GPA float64
|
||||||
|
NeverMind string `ini:"-"`
|
||||||
|
*Embeded
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
a := &Author{"Unknwon", true, 21, 2.8, "",
|
||||||
|
&Embeded{
|
||||||
|
[]time.Time{time.Now(), time.Now()},
|
||||||
|
[]string{"HangZhou", "Boston"},
|
||||||
|
[]int{},
|
||||||
|
}}
|
||||||
|
cfg := ini.Empty()
|
||||||
|
err = ini.ReflectFrom(cfg, a)
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
So, what do I get?
|
||||||
|
|
||||||
|
```ini
|
||||||
|
NAME = Unknwon
|
||||||
|
Male = true
|
||||||
|
Age = 21
|
||||||
|
GPA = 2.8
|
||||||
|
|
||||||
|
[Embeded]
|
||||||
|
Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00
|
||||||
|
places = HangZhou,Boston
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Name Mapper
|
||||||
|
|
||||||
|
To save your time and make your code cleaner, this library supports [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) between struct field and actual section and key name.
|
||||||
|
|
||||||
|
There are 2 built-in name mappers:
|
||||||
|
|
||||||
|
- `AllCapsUnderscore`: it converts to format `ALL_CAPS_UNDERSCORE` then match section or key.
|
||||||
|
- `TitleUnderscore`: it converts to format `title_underscore` then match section or key.
|
||||||
|
|
||||||
|
To use them:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Info struct {
|
||||||
|
PackageName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("package_name=ini"))
|
||||||
|
// ...
|
||||||
|
|
||||||
|
cfg, err := ini.Load([]byte("PACKAGE_NAME=ini"))
|
||||||
|
// ...
|
||||||
|
info := new(Info)
|
||||||
|
cfg.NameMapper = ini.AllCapsUnderscore
|
||||||
|
err = cfg.MapTo(info)
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Same rules of name mapper apply to `ini.ReflectFromWithMapper` function.
|
||||||
|
|
||||||
|
#### Value Mapper
|
||||||
|
|
||||||
|
To expand values (e.g. from environment variables), you can use the `ValueMapper` to transform values:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Env struct {
|
||||||
|
Foo string `ini:"foo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg, err := ini.Load([]byte("[env]\nfoo = ${MY_VAR}\n")
|
||||||
|
cfg.ValueMapper = os.ExpandEnv
|
||||||
|
// ...
|
||||||
|
env := &Env{}
|
||||||
|
err = cfg.Section("env").MapTo(env)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This would set the value of `env.Foo` to the value of the environment variable `MY_VAR`.
|
||||||
|
|
||||||
|
#### Other Notes On Map/Reflect
|
||||||
|
|
||||||
|
Any embedded struct is treated as a section by default, and there is no automatic parent-child relations in map/reflect feature:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Child struct {
|
||||||
|
Age string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Child
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
City string
|
||||||
|
Parent
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
City = Boston
|
||||||
|
|
||||||
|
[Parent]
|
||||||
|
Name = Unknwon
|
||||||
|
|
||||||
|
[Child]
|
||||||
|
Age = 21
|
||||||
|
```
|
||||||
|
|
||||||
|
What if, yes, I'm paranoid, I want embedded struct to be in the same section. Well, all roads lead to Rome.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Child struct {
|
||||||
|
Age string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Child `ini:"Parent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
City string
|
||||||
|
Parent
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
City = Boston
|
||||||
|
|
||||||
|
[Parent]
|
||||||
|
Name = Unknwon
|
||||||
|
Age = 21
|
||||||
|
```
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
- [API Documentation](https://gowalker.org/gopkg.in/ini.v1)
|
||||||
|
- [File An Issue](https://github.com/go-ini/ini/issues/new)
|
||||||
|
|
||||||
|
## FAQs
|
||||||
|
|
||||||
|
### What does `BlockMode` field do?
|
||||||
|
|
||||||
|
By default, library lets you read and write values so we need a locker to make sure your data is safe. But in cases that you are very sure about only reading data through the library, you can set `cfg.BlockMode = false` to speed up read operations about **50-70%** faster.
|
||||||
|
|
||||||
|
### Why another INI library?
|
||||||
|
|
||||||
|
Many people are using my another INI library [goconfig](https://github.com/Unknwon/goconfig), so the reason for this one is I would like to make more Go style code. Also when you set `cfg.BlockMode = false`, this one is about **10-30%** faster.
|
||||||
|
|
||||||
|
To make those changes I have to confirm API broken, so it's safer to keep it in another place and start using `gopkg.in` to version my package at this time.(PS: shorter import path)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.
|
690
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/README_ZH.md
generated
vendored
Normal file
690
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/README_ZH.md
generated
vendored
Normal file
|
@ -0,0 +1,690 @@
|
||||||
|
本包提供了 Go 语言中读写 INI 文件的功能。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- 支持覆盖加载多个数据源(`[]byte` 或文件)
|
||||||
|
- 支持递归读取键值
|
||||||
|
- 支持读取父子分区
|
||||||
|
- 支持读取自增键名
|
||||||
|
- 支持读取多行的键值
|
||||||
|
- 支持大量辅助方法
|
||||||
|
- 支持在读取时直接转换为 Go 语言类型
|
||||||
|
- 支持读取和 **写入** 分区和键的注释
|
||||||
|
- 轻松操作分区、键值和注释
|
||||||
|
- 在保存文件时分区和键值会保持原有的顺序
|
||||||
|
|
||||||
|
## 下载安装
|
||||||
|
|
||||||
|
使用一个特定版本:
|
||||||
|
|
||||||
|
go get gopkg.in/ini.v1
|
||||||
|
|
||||||
|
使用最新版:
|
||||||
|
|
||||||
|
go get github.com/go-ini/ini
|
||||||
|
|
||||||
|
如需更新请添加 `-u` 选项。
|
||||||
|
|
||||||
|
### 测试安装
|
||||||
|
|
||||||
|
如果您想要在自己的机器上运行测试,请使用 `-t` 标记:
|
||||||
|
|
||||||
|
go get -t gopkg.in/ini.v1
|
||||||
|
|
||||||
|
如需更新请添加 `-u` 选项。
|
||||||
|
|
||||||
|
## 开始使用
|
||||||
|
|
||||||
|
### 从数据源加载
|
||||||
|
|
||||||
|
一个 **数据源** 可以是 `[]byte` 类型的原始数据,或 `string` 类型的文件路径。您可以加载 **任意多个** 数据源。如果您传递其它类型的数据源,则会直接返回错误。
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg, err := ini.Load([]byte("raw data"), "filename")
|
||||||
|
```
|
||||||
|
|
||||||
|
或者从一个空白的文件开始:
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg := ini.Empty()
|
||||||
|
```
|
||||||
|
|
||||||
|
当您在一开始无法决定需要加载哪些数据源时,仍可以使用 **Append()** 在需要的时候加载它们。
|
||||||
|
|
||||||
|
```go
|
||||||
|
err := cfg.Append("other file", []byte("other raw data"))
|
||||||
|
```
|
||||||
|
|
||||||
|
当您想要加载一系列文件,但是不能够确定其中哪些文件是不存在的,可以通过调用函数 `LooseLoad` 来忽略它们(`Load` 会因为文件不存在而返回错误):
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg, err := ini.LooseLoad("filename", "filename_404")
|
||||||
|
```
|
||||||
|
|
||||||
|
更牛逼的是,当那些之前不存在的文件在重新调用 `Reload` 方法的时候突然出现了,那么它们会被正常加载。
|
||||||
|
|
||||||
|
#### 忽略键名的大小写
|
||||||
|
|
||||||
|
有时候分区和键的名称大小写混合非常烦人,这个时候就可以通过 `InsensitiveLoad` 将所有分区和键名在读取里强制转换为小写:
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg, err := ini.InsensitiveLoad("filename")
|
||||||
|
//...
|
||||||
|
|
||||||
|
// sec1 和 sec2 指向同一个分区对象
|
||||||
|
sec1, err := cfg.GetSection("Section")
|
||||||
|
sec2, err := cfg.GetSection("SecTIOn")
|
||||||
|
|
||||||
|
// key1 和 key2 指向同一个键对象
|
||||||
|
key1, err := cfg.GetKey("Key")
|
||||||
|
key2, err := cfg.GetKey("KeY")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 类似 MySQL 配置中的布尔值键
|
||||||
|
|
||||||
|
MySQL 的配置文件中会出现没有具体值的布尔类型的键:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[mysqld]
|
||||||
|
...
|
||||||
|
skip-host-cache
|
||||||
|
skip-name-resolve
|
||||||
|
```
|
||||||
|
|
||||||
|
默认情况下这被认为是缺失值而无法完成解析,但可以通过高级的加载选项对它们进行处理:
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
|
||||||
|
```
|
||||||
|
|
||||||
|
这些键的值永远为 `true`,且在保存到文件时也只会输出键名。
|
||||||
|
|
||||||
|
### 操作分区(Section)
|
||||||
|
|
||||||
|
获取指定分区:
|
||||||
|
|
||||||
|
```go
|
||||||
|
section, err := cfg.GetSection("section name")
|
||||||
|
```
|
||||||
|
|
||||||
|
如果您想要获取默认分区,则可以用空字符串代替分区名:
|
||||||
|
|
||||||
|
```go
|
||||||
|
section, err := cfg.GetSection("")
|
||||||
|
```
|
||||||
|
|
||||||
|
当您非常确定某个分区是存在的,可以使用以下简便方法:
|
||||||
|
|
||||||
|
```go
|
||||||
|
section := cfg.Section("")
|
||||||
|
```
|
||||||
|
|
||||||
|
如果不小心判断错了,要获取的分区其实是不存在的,那会发生什么呢?没事的,它会自动创建并返回一个对应的分区对象给您。
|
||||||
|
|
||||||
|
创建一个分区:
|
||||||
|
|
||||||
|
```go
|
||||||
|
err := cfg.NewSection("new section")
|
||||||
|
```
|
||||||
|
|
||||||
|
获取所有分区对象或名称:
|
||||||
|
|
||||||
|
```go
|
||||||
|
sections := cfg.Sections()
|
||||||
|
names := cfg.SectionStrings()
|
||||||
|
```
|
||||||
|
|
||||||
|
### 操作键(Key)
|
||||||
|
|
||||||
|
获取某个分区下的键:
|
||||||
|
|
||||||
|
```go
|
||||||
|
key, err := cfg.Section("").GetKey("key name")
|
||||||
|
```
|
||||||
|
|
||||||
|
和分区一样,您也可以直接获取键而忽略错误处理:
|
||||||
|
|
||||||
|
```go
|
||||||
|
key := cfg.Section("").Key("key name")
|
||||||
|
```
|
||||||
|
|
||||||
|
判断某个键是否存在:
|
||||||
|
|
||||||
|
```go
|
||||||
|
yes := cfg.Section("").HasKey("key name")
|
||||||
|
```
|
||||||
|
|
||||||
|
创建一个新的键:
|
||||||
|
|
||||||
|
```go
|
||||||
|
err := cfg.Section("").NewKey("name", "value")
|
||||||
|
```
|
||||||
|
|
||||||
|
获取分区下的所有键或键名:
|
||||||
|
|
||||||
|
```go
|
||||||
|
keys := cfg.Section("").Keys()
|
||||||
|
names := cfg.Section("").KeyStrings()
|
||||||
|
```
|
||||||
|
|
||||||
|
获取分区下的所有键值对的克隆:
|
||||||
|
|
||||||
|
```go
|
||||||
|
hash := cfg.Section("").KeysHash()
|
||||||
|
```
|
||||||
|
|
||||||
|
### 操作键值(Value)
|
||||||
|
|
||||||
|
获取一个类型为字符串(string)的值:
|
||||||
|
|
||||||
|
```go
|
||||||
|
val := cfg.Section("").Key("key name").String()
|
||||||
|
```
|
||||||
|
|
||||||
|
获取值的同时通过自定义函数进行处理验证:
|
||||||
|
|
||||||
|
```go
|
||||||
|
val := cfg.Section("").Key("key name").Validate(func(in string) string {
|
||||||
|
if len(in) == 0 {
|
||||||
|
return "default"
|
||||||
|
}
|
||||||
|
return in
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
如果您不需要任何对值的自动转变功能(例如递归读取),可以直接获取原值(这种方式性能最佳):
|
||||||
|
|
||||||
|
```go
|
||||||
|
val := cfg.Section("").Key("key name").Value()
|
||||||
|
```
|
||||||
|
|
||||||
|
判断某个原值是否存在:
|
||||||
|
|
||||||
|
```go
|
||||||
|
yes := cfg.Section("").HasValue("test value")
|
||||||
|
```
|
||||||
|
|
||||||
|
获取其它类型的值:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 布尔值的规则:
|
||||||
|
// true 当值为:1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On
|
||||||
|
// false 当值为:0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off
|
||||||
|
v, err = cfg.Section("").Key("BOOL").Bool()
|
||||||
|
v, err = cfg.Section("").Key("FLOAT64").Float64()
|
||||||
|
v, err = cfg.Section("").Key("INT").Int()
|
||||||
|
v, err = cfg.Section("").Key("INT64").Int64()
|
||||||
|
v, err = cfg.Section("").Key("UINT").Uint()
|
||||||
|
v, err = cfg.Section("").Key("UINT64").Uint64()
|
||||||
|
v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339)
|
||||||
|
v, err = cfg.Section("").Key("TIME").Time() // RFC3339
|
||||||
|
|
||||||
|
v = cfg.Section("").Key("BOOL").MustBool()
|
||||||
|
v = cfg.Section("").Key("FLOAT64").MustFloat64()
|
||||||
|
v = cfg.Section("").Key("INT").MustInt()
|
||||||
|
v = cfg.Section("").Key("INT64").MustInt64()
|
||||||
|
v = cfg.Section("").Key("UINT").MustUint()
|
||||||
|
v = cfg.Section("").Key("UINT64").MustUint64()
|
||||||
|
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339)
|
||||||
|
v = cfg.Section("").Key("TIME").MustTime() // RFC3339
|
||||||
|
|
||||||
|
// 由 Must 开头的方法名允许接收一个相同类型的参数来作为默认值,
|
||||||
|
// 当键不存在或者转换失败时,则会直接返回该默认值。
|
||||||
|
// 但是,MustString 方法必须传递一个默认值。
|
||||||
|
|
||||||
|
v = cfg.Seciont("").Key("String").MustString("default")
|
||||||
|
v = cfg.Section("").Key("BOOL").MustBool(true)
|
||||||
|
v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25)
|
||||||
|
v = cfg.Section("").Key("INT").MustInt(10)
|
||||||
|
v = cfg.Section("").Key("INT64").MustInt64(99)
|
||||||
|
v = cfg.Section("").Key("UINT").MustUint(3)
|
||||||
|
v = cfg.Section("").Key("UINT64").MustUint64(6)
|
||||||
|
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now())
|
||||||
|
v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339
|
||||||
|
```
|
||||||
|
|
||||||
|
如果我的值有好多行怎么办?
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[advance]
|
||||||
|
ADDRESS = """404 road,
|
||||||
|
NotFound, State, 5000
|
||||||
|
Earth"""
|
||||||
|
```
|
||||||
|
|
||||||
|
嗯哼?小 case!
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("advance").Key("ADDRESS").String()
|
||||||
|
|
||||||
|
/* --- start ---
|
||||||
|
404 road,
|
||||||
|
NotFound, State, 5000
|
||||||
|
Earth
|
||||||
|
------ end --- */
|
||||||
|
```
|
||||||
|
|
||||||
|
赞爆了!那要是我属于一行的内容写不下想要写到第二行怎么办?
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[advance]
|
||||||
|
two_lines = how about \
|
||||||
|
continuation lines?
|
||||||
|
lots_of_lines = 1 \
|
||||||
|
2 \
|
||||||
|
3 \
|
||||||
|
4
|
||||||
|
```
|
||||||
|
|
||||||
|
简直是小菜一碟!
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("advance").Key("two_lines").String() // how about continuation lines?
|
||||||
|
cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4
|
||||||
|
```
|
||||||
|
|
||||||
|
可是我有时候觉得两行连在一起特别没劲,怎么才能不自动连接两行呢?
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg, err := ini.LoadSources(ini.LoadOptions{
|
||||||
|
IgnoreContinuation: true,
|
||||||
|
}, "filename")
|
||||||
|
```
|
||||||
|
|
||||||
|
哇靠给力啊!
|
||||||
|
|
||||||
|
需要注意的是,值两侧的单引号会被自动剔除:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
foo = "some value" // foo: some value
|
||||||
|
bar = 'some value' // bar: some value
|
||||||
|
```
|
||||||
|
|
||||||
|
这就是全部了?哈哈,当然不是。
|
||||||
|
|
||||||
|
#### 操作键值的辅助方法
|
||||||
|
|
||||||
|
获取键值时设定候选值:
|
||||||
|
|
||||||
|
```go
|
||||||
|
v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"})
|
||||||
|
v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75})
|
||||||
|
v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30})
|
||||||
|
v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30})
|
||||||
|
v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9})
|
||||||
|
v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9})
|
||||||
|
v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3})
|
||||||
|
v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339
|
||||||
|
```
|
||||||
|
|
||||||
|
如果获取到的值不是候选值的任意一个,则会返回默认值,而默认值不需要是候选值中的一员。
|
||||||
|
|
||||||
|
验证获取的值是否在指定范围内:
|
||||||
|
|
||||||
|
```go
|
||||||
|
vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2)
|
||||||
|
vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20)
|
||||||
|
vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20)
|
||||||
|
vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9)
|
||||||
|
vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9)
|
||||||
|
vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime)
|
||||||
|
vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 自动分割键值到切片(slice)
|
||||||
|
|
||||||
|
当存在无效输入时,使用零值代替:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
|
||||||
|
// Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0]
|
||||||
|
vals = cfg.Section("").Key("STRINGS").Strings(",")
|
||||||
|
vals = cfg.Section("").Key("FLOAT64S").Float64s(",")
|
||||||
|
vals = cfg.Section("").Key("INTS").Ints(",")
|
||||||
|
vals = cfg.Section("").Key("INT64S").Int64s(",")
|
||||||
|
vals = cfg.Section("").Key("UINTS").Uints(",")
|
||||||
|
vals = cfg.Section("").Key("UINT64S").Uint64s(",")
|
||||||
|
vals = cfg.Section("").Key("TIMES").Times(",")
|
||||||
|
```
|
||||||
|
|
||||||
|
从结果切片中剔除无效输入:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
|
||||||
|
// Input: how, 2.2, are, you -> [2.2]
|
||||||
|
vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",")
|
||||||
|
vals = cfg.Section("").Key("INTS").ValidInts(",")
|
||||||
|
vals = cfg.Section("").Key("INT64S").ValidInt64s(",")
|
||||||
|
vals = cfg.Section("").Key("UINTS").ValidUints(",")
|
||||||
|
vals = cfg.Section("").Key("UINT64S").ValidUint64s(",")
|
||||||
|
vals = cfg.Section("").Key("TIMES").ValidTimes(",")
|
||||||
|
```
|
||||||
|
|
||||||
|
当存在无效输入时,直接返回错误:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
|
||||||
|
// Input: how, 2.2, are, you -> error
|
||||||
|
vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",")
|
||||||
|
vals = cfg.Section("").Key("INTS").StrictInts(",")
|
||||||
|
vals = cfg.Section("").Key("INT64S").StrictInt64s(",")
|
||||||
|
vals = cfg.Section("").Key("UINTS").StrictUints(",")
|
||||||
|
vals = cfg.Section("").Key("UINT64S").StrictUint64s(",")
|
||||||
|
vals = cfg.Section("").Key("TIMES").StrictTimes(",")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 保存配置
|
||||||
|
|
||||||
|
终于到了这个时刻,是时候保存一下配置了。
|
||||||
|
|
||||||
|
比较原始的做法是输出配置到某个文件:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// ...
|
||||||
|
err = cfg.SaveTo("my.ini")
|
||||||
|
err = cfg.SaveToIndent("my.ini", "\t")
|
||||||
|
```
|
||||||
|
|
||||||
|
另一个比较高级的做法是写入到任何实现 `io.Writer` 接口的对象中:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// ...
|
||||||
|
cfg.WriteTo(writer)
|
||||||
|
cfg.WriteToIndent(writer, "\t")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 高级用法
|
||||||
|
|
||||||
|
#### 递归读取键值
|
||||||
|
|
||||||
|
在获取所有键值的过程中,特殊语法 `%(<name>)s` 会被应用,其中 `<name>` 可以是相同分区或者默认分区下的键名。字符串 `%(<name>)s` 会被相应的键值所替代,如果指定的键不存在,则会用空字符串替代。您可以最多使用 99 层的递归嵌套。
|
||||||
|
|
||||||
|
```ini
|
||||||
|
NAME = ini
|
||||||
|
|
||||||
|
[author]
|
||||||
|
NAME = Unknwon
|
||||||
|
GITHUB = https://github.com/%(NAME)s
|
||||||
|
|
||||||
|
[package]
|
||||||
|
FULL_NAME = github.com/go-ini/%(NAME)s
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon
|
||||||
|
cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 读取父子分区
|
||||||
|
|
||||||
|
您可以在分区名称中使用 `.` 来表示两个或多个分区之间的父子关系。如果某个键在子分区中不存在,则会去它的父分区中再次寻找,直到没有父分区为止。
|
||||||
|
|
||||||
|
```ini
|
||||||
|
NAME = ini
|
||||||
|
VERSION = v1
|
||||||
|
IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
|
||||||
|
|
||||||
|
[package]
|
||||||
|
CLONE_URL = https://%(IMPORT_PATH)s
|
||||||
|
|
||||||
|
[package.sub]
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 获取上级父分区下的所有键名
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 读取自增键名
|
||||||
|
|
||||||
|
如果数据源中的键名为 `-`,则认为该键使用了自增键名的特殊语法。计数器从 1 开始,并且分区之间是相互独立的。
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[features]
|
||||||
|
-: Support read/write comments of keys and sections
|
||||||
|
-: Support auto-increment of key names
|
||||||
|
-: Support load multiple files to overwrite key values
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 映射到结构
|
||||||
|
|
||||||
|
想要使用更加面向对象的方式玩转 INI 吗?好主意。
|
||||||
|
|
||||||
|
```ini
|
||||||
|
Name = Unknwon
|
||||||
|
age = 21
|
||||||
|
Male = true
|
||||||
|
Born = 1993-01-01T20:17:05Z
|
||||||
|
|
||||||
|
[Note]
|
||||||
|
Content = Hi is a good man!
|
||||||
|
Cities = HangZhou, Boston
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Note struct {
|
||||||
|
Content string
|
||||||
|
Cities []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
Name string
|
||||||
|
Age int `ini:"age"`
|
||||||
|
Male bool
|
||||||
|
Born time.Time
|
||||||
|
Note
|
||||||
|
Created time.Time `ini:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg, err := ini.Load("path/to/ini")
|
||||||
|
// ...
|
||||||
|
p := new(Person)
|
||||||
|
err = cfg.MapTo(p)
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// 一切竟可以如此的简单。
|
||||||
|
err = ini.MapTo(p, "path/to/ini")
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// 嗯哼?只需要映射一个分区吗?
|
||||||
|
n := new(Note)
|
||||||
|
err = cfg.Section("Note").MapTo(n)
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
结构的字段怎么设置默认值呢?很简单,只要在映射之前对指定字段进行赋值就可以了。如果键未找到或者类型错误,该值不会发生改变。
|
||||||
|
|
||||||
|
```go
|
||||||
|
// ...
|
||||||
|
p := &Person{
|
||||||
|
Name: "Joe",
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
|
||||||
|
这样玩 INI 真的好酷啊!然而,如果不能还给我原来的配置文件,有什么卵用?
|
||||||
|
|
||||||
|
### 从结构反射
|
||||||
|
|
||||||
|
可是,我有说不能吗?
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Embeded struct {
|
||||||
|
Dates []time.Time `delim:"|"`
|
||||||
|
Places []string `ini:"places,omitempty"`
|
||||||
|
None []int `ini:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Author struct {
|
||||||
|
Name string `ini:"NAME"`
|
||||||
|
Male bool
|
||||||
|
Age int
|
||||||
|
GPA float64
|
||||||
|
NeverMind string `ini:"-"`
|
||||||
|
*Embeded
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
a := &Author{"Unknwon", true, 21, 2.8, "",
|
||||||
|
&Embeded{
|
||||||
|
[]time.Time{time.Now(), time.Now()},
|
||||||
|
[]string{"HangZhou", "Boston"},
|
||||||
|
[]int{},
|
||||||
|
}}
|
||||||
|
cfg := ini.Empty()
|
||||||
|
err = ini.ReflectFrom(cfg, a)
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
瞧瞧,奇迹发生了。
|
||||||
|
|
||||||
|
```ini
|
||||||
|
NAME = Unknwon
|
||||||
|
Male = true
|
||||||
|
Age = 21
|
||||||
|
GPA = 2.8
|
||||||
|
|
||||||
|
[Embeded]
|
||||||
|
Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00
|
||||||
|
places = HangZhou,Boston
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 名称映射器(Name Mapper)
|
||||||
|
|
||||||
|
为了节省您的时间并简化代码,本库支持类型为 [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) 的名称映射器,该映射器负责结构字段名与分区名和键名之间的映射。
|
||||||
|
|
||||||
|
目前有 2 款内置的映射器:
|
||||||
|
|
||||||
|
- `AllCapsUnderscore`:该映射器将字段名转换至格式 `ALL_CAPS_UNDERSCORE` 后再去匹配分区名和键名。
|
||||||
|
- `TitleUnderscore`:该映射器将字段名转换至格式 `title_underscore` 后再去匹配分区名和键名。
|
||||||
|
|
||||||
|
使用方法:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Info struct{
|
||||||
|
PackageName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("package_name=ini"))
|
||||||
|
// ...
|
||||||
|
|
||||||
|
cfg, err := ini.Load([]byte("PACKAGE_NAME=ini"))
|
||||||
|
// ...
|
||||||
|
info := new(Info)
|
||||||
|
cfg.NameMapper = ini.AllCapsUnderscore
|
||||||
|
err = cfg.MapTo(info)
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
使用函数 `ini.ReflectFromWithMapper` 时也可应用相同的规则。
|
||||||
|
|
||||||
|
#### 值映射器(Value Mapper)
|
||||||
|
|
||||||
|
值映射器允许使用一个自定义函数自动展开值的具体内容,例如:运行时获取环境变量:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Env struct {
|
||||||
|
Foo string `ini:"foo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg, err := ini.Load([]byte("[env]\nfoo = ${MY_VAR}\n")
|
||||||
|
cfg.ValueMapper = os.ExpandEnv
|
||||||
|
// ...
|
||||||
|
env := &Env{}
|
||||||
|
err = cfg.Section("env").MapTo(env)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
本例中,`env.Foo` 将会是运行时所获取到环境变量 `MY_VAR` 的值。
|
||||||
|
|
||||||
|
#### 映射/反射的其它说明
|
||||||
|
|
||||||
|
任何嵌入的结构都会被默认认作一个不同的分区,并且不会自动产生所谓的父子分区关联:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Child struct {
|
||||||
|
Age string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Child
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
City string
|
||||||
|
Parent
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
示例配置文件:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
City = Boston
|
||||||
|
|
||||||
|
[Parent]
|
||||||
|
Name = Unknwon
|
||||||
|
|
||||||
|
[Child]
|
||||||
|
Age = 21
|
||||||
|
```
|
||||||
|
|
||||||
|
很好,但是,我就是要嵌入结构也在同一个分区。好吧,你爹是李刚!
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Child struct {
|
||||||
|
Age string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parent struct {
|
||||||
|
Name string
|
||||||
|
Child `ini:"Parent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
City string
|
||||||
|
Parent
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
示例配置文件:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
City = Boston
|
||||||
|
|
||||||
|
[Parent]
|
||||||
|
Name = Unknwon
|
||||||
|
Age = 21
|
||||||
|
```
|
||||||
|
|
||||||
|
## 获取帮助
|
||||||
|
|
||||||
|
- [API 文档](https://gowalker.org/gopkg.in/ini.v1)
|
||||||
|
- [创建工单](https://github.com/go-ini/ini/issues/new)
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 字段 `BlockMode` 是什么?
|
||||||
|
|
||||||
|
默认情况下,本库会在您进行读写操作时采用锁机制来确保数据时间。但在某些情况下,您非常确定只进行读操作。此时,您可以通过设置 `cfg.BlockMode = false` 来将读操作提升大约 **50-70%** 的性能。
|
||||||
|
|
||||||
|
### 为什么要写另一个 INI 解析库?
|
||||||
|
|
||||||
|
许多人都在使用我的 [goconfig](https://github.com/Unknwon/goconfig) 来完成对 INI 文件的操作,但我希望使用更加 Go 风格的代码。并且当您设置 `cfg.BlockMode = false` 时,会有大约 **10-30%** 的性能提升。
|
||||||
|
|
||||||
|
为了做出这些改变,我必须对 API 进行破坏,所以新开一个仓库是最安全的做法。除此之外,本库直接使用 `gopkg.in` 来进行版本化发布。(其实真相是导入路径更短了)
|
32
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/error.go
generated
vendored
Normal file
32
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/error.go
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2016 Unknwon
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package ini
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrDelimiterNotFound struct {
|
||||||
|
Line string
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsErrDelimiterNotFound(err error) bool {
|
||||||
|
_, ok := err.(ErrDelimiterNotFound)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrDelimiterNotFound) Error() string {
|
||||||
|
return fmt.Sprintf("key-value delimiter not found: %s", err.Line)
|
||||||
|
}
|
501
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/ini.go
generated
vendored
Normal file
501
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/ini.go
generated
vendored
Normal file
|
@ -0,0 +1,501 @@
|
||||||
|
// Copyright 2014 Unknwon
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Package ini provides INI file read and write functionality in Go.
|
||||||
|
package ini
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Name for default section. You can use this constant or the string literal.
|
||||||
|
// In most of cases, an empty string is all you need to access the section.
|
||||||
|
DEFAULT_SECTION = "DEFAULT"
|
||||||
|
|
||||||
|
// Maximum allowed depth when recursively substituing variable names.
|
||||||
|
_DEPTH_VALUES = 99
|
||||||
|
_VERSION = "1.21.1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Version returns current package version literal.
|
||||||
|
func Version() string {
|
||||||
|
return _VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Delimiter to determine or compose a new line.
|
||||||
|
// This variable will be changed to "\r\n" automatically on Windows
|
||||||
|
// at package init time.
|
||||||
|
LineBreak = "\n"
|
||||||
|
|
||||||
|
// Variable regexp pattern: %(variable)s
|
||||||
|
varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`)
|
||||||
|
|
||||||
|
// Indicate whether to align "=" sign with spaces to produce pretty output
|
||||||
|
// or reduce all possible spaces for compact format.
|
||||||
|
PrettyFormat = true
|
||||||
|
|
||||||
|
// Explicitly write DEFAULT section header
|
||||||
|
DefaultHeader = false
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
LineBreak = "\r\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func inSlice(str string, s []string) bool {
|
||||||
|
for _, v := range s {
|
||||||
|
if str == v {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// dataSource is an interface that returns object which can be read and closed.
|
||||||
|
type dataSource interface {
|
||||||
|
ReadCloser() (io.ReadCloser, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sourceFile represents an object that contains content on the local file system.
|
||||||
|
type sourceFile struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) {
|
||||||
|
return os.Open(s.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
type bytesReadCloser struct {
|
||||||
|
reader io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *bytesReadCloser) Read(p []byte) (n int, err error) {
|
||||||
|
return rc.reader.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *bytesReadCloser) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sourceData represents an object that contains content in memory.
|
||||||
|
type sourceData struct {
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sourceData) ReadCloser() (io.ReadCloser, error) {
|
||||||
|
return &bytesReadCloser{bytes.NewReader(s.data)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// File represents a combination of a or more INI file(s) in memory.
|
||||||
|
type File struct {
|
||||||
|
// Should make things safe, but sometimes doesn't matter.
|
||||||
|
BlockMode bool
|
||||||
|
// Make sure data is safe in multiple goroutines.
|
||||||
|
lock sync.RWMutex
|
||||||
|
|
||||||
|
// Allow combination of multiple data sources.
|
||||||
|
dataSources []dataSource
|
||||||
|
// Actual data is stored here.
|
||||||
|
sections map[string]*Section
|
||||||
|
|
||||||
|
// To keep data in order.
|
||||||
|
sectionList []string
|
||||||
|
|
||||||
|
options LoadOptions
|
||||||
|
|
||||||
|
NameMapper
|
||||||
|
ValueMapper
|
||||||
|
}
|
||||||
|
|
||||||
|
// newFile initializes File object with given data sources.
|
||||||
|
func newFile(dataSources []dataSource, opts LoadOptions) *File {
|
||||||
|
return &File{
|
||||||
|
BlockMode: true,
|
||||||
|
dataSources: dataSources,
|
||||||
|
sections: make(map[string]*Section),
|
||||||
|
sectionList: make([]string, 0, 10),
|
||||||
|
options: opts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDataSource(source interface{}) (dataSource, error) {
|
||||||
|
switch s := source.(type) {
|
||||||
|
case string:
|
||||||
|
return sourceFile{s}, nil
|
||||||
|
case []byte:
|
||||||
|
return &sourceData{s}, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("error parsing data source: unknown type '%s'", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoadOptions struct {
|
||||||
|
// Loose indicates whether the parser should ignore nonexistent files or return error.
|
||||||
|
Loose bool
|
||||||
|
// Insensitive indicates whether the parser forces all section and key names to lowercase.
|
||||||
|
Insensitive bool
|
||||||
|
// IgnoreContinuation indicates whether to ignore continuation lines while parsing.
|
||||||
|
IgnoreContinuation bool
|
||||||
|
// AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing.
|
||||||
|
// This type of keys are mostly used in my.cnf.
|
||||||
|
AllowBooleanKeys bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) {
|
||||||
|
sources := make([]dataSource, len(others)+1)
|
||||||
|
sources[0], err = parseDataSource(source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := range others {
|
||||||
|
sources[i+1], err = parseDataSource(others[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f := newFile(sources, opts)
|
||||||
|
if err = f.Reload(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load loads and parses from INI data sources.
|
||||||
|
// Arguments can be mixed of file name with string type, or raw data in []byte.
|
||||||
|
// It will return error if list contains nonexistent files.
|
||||||
|
func Load(source interface{}, others ...interface{}) (*File, error) {
|
||||||
|
return LoadSources(LoadOptions{}, source, others...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LooseLoad has exactly same functionality as Load function
|
||||||
|
// except it ignores nonexistent files instead of returning error.
|
||||||
|
func LooseLoad(source interface{}, others ...interface{}) (*File, error) {
|
||||||
|
return LoadSources(LoadOptions{Loose: true}, source, others...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsensitiveLoad has exactly same functionality as Load function
|
||||||
|
// except it forces all section and key names to be lowercased.
|
||||||
|
func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) {
|
||||||
|
return LoadSources(LoadOptions{Insensitive: true}, source, others...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty returns an empty file object.
|
||||||
|
func Empty() *File {
|
||||||
|
// Ignore error here, we sure our data is good.
|
||||||
|
f, _ := Load([]byte(""))
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSection creates a new section.
|
||||||
|
func (f *File) NewSection(name string) (*Section, error) {
|
||||||
|
if len(name) == 0 {
|
||||||
|
return nil, errors.New("error creating new section: empty section name")
|
||||||
|
} else if f.options.Insensitive && name != DEFAULT_SECTION {
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.BlockMode {
|
||||||
|
f.lock.Lock()
|
||||||
|
defer f.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if inSlice(name, f.sectionList) {
|
||||||
|
return f.sections[name], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f.sectionList = append(f.sectionList, name)
|
||||||
|
f.sections[name] = newSection(f, name)
|
||||||
|
return f.sections[name], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSections creates a list of sections.
|
||||||
|
func (f *File) NewSections(names ...string) (err error) {
|
||||||
|
for _, name := range names {
|
||||||
|
if _, err = f.NewSection(name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSection returns section by given name.
|
||||||
|
func (f *File) GetSection(name string) (*Section, error) {
|
||||||
|
if len(name) == 0 {
|
||||||
|
name = DEFAULT_SECTION
|
||||||
|
} else if f.options.Insensitive {
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.BlockMode {
|
||||||
|
f.lock.RLock()
|
||||||
|
defer f.lock.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
sec := f.sections[name]
|
||||||
|
if sec == nil {
|
||||||
|
return nil, fmt.Errorf("section '%s' does not exist", name)
|
||||||
|
}
|
||||||
|
return sec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section assumes named section exists and returns a zero-value when not.
|
||||||
|
func (f *File) Section(name string) *Section {
|
||||||
|
sec, err := f.GetSection(name)
|
||||||
|
if err != nil {
|
||||||
|
// Note: It's OK here because the only possible error is empty section name,
|
||||||
|
// but if it's empty, this piece of code won't be executed.
|
||||||
|
sec, _ = f.NewSection(name)
|
||||||
|
return sec
|
||||||
|
}
|
||||||
|
return sec
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section returns list of Section.
|
||||||
|
func (f *File) Sections() []*Section {
|
||||||
|
sections := make([]*Section, len(f.sectionList))
|
||||||
|
for i := range f.sectionList {
|
||||||
|
sections[i] = f.Section(f.sectionList[i])
|
||||||
|
}
|
||||||
|
return sections
|
||||||
|
}
|
||||||
|
|
||||||
|
// SectionStrings returns list of section names.
|
||||||
|
func (f *File) SectionStrings() []string {
|
||||||
|
list := make([]string, len(f.sectionList))
|
||||||
|
copy(list, f.sectionList)
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSection deletes a section.
|
||||||
|
func (f *File) DeleteSection(name string) {
|
||||||
|
if f.BlockMode {
|
||||||
|
f.lock.Lock()
|
||||||
|
defer f.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(name) == 0 {
|
||||||
|
name = DEFAULT_SECTION
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, s := range f.sectionList {
|
||||||
|
if s == name {
|
||||||
|
f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...)
|
||||||
|
delete(f.sections, name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) reload(s dataSource) error {
|
||||||
|
r, err := s.ReadCloser()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
return f.parse(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload reloads and parses all data sources.
|
||||||
|
func (f *File) Reload() (err error) {
|
||||||
|
for _, s := range f.dataSources {
|
||||||
|
if err = f.reload(s); err != nil {
|
||||||
|
// In loose mode, we create an empty default section for nonexistent files.
|
||||||
|
if os.IsNotExist(err) && f.options.Loose {
|
||||||
|
f.parse(bytes.NewBuffer(nil))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append appends one or more data sources and reloads automatically.
|
||||||
|
func (f *File) Append(source interface{}, others ...interface{}) error {
|
||||||
|
ds, err := parseDataSource(source)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.dataSources = append(f.dataSources, ds)
|
||||||
|
for _, s := range others {
|
||||||
|
ds, err = parseDataSource(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.dataSources = append(f.dataSources, ds)
|
||||||
|
}
|
||||||
|
return f.Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteToIndent writes content into io.Writer with given indention.
|
||||||
|
// If PrettyFormat has been set to be true,
|
||||||
|
// it will align "=" sign with spaces under each section.
|
||||||
|
func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) {
|
||||||
|
equalSign := "="
|
||||||
|
if PrettyFormat {
|
||||||
|
equalSign = " = "
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use buffer to make sure target is safe until finish encoding.
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
for i, sname := range f.sectionList {
|
||||||
|
sec := f.Section(sname)
|
||||||
|
if len(sec.Comment) > 0 {
|
||||||
|
if sec.Comment[0] != '#' && sec.Comment[0] != ';' {
|
||||||
|
sec.Comment = "; " + sec.Comment
|
||||||
|
}
|
||||||
|
if _, err = buf.WriteString(sec.Comment + LineBreak); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > 0 || DefaultHeader {
|
||||||
|
if _, err = buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Write nothing if default section is empty
|
||||||
|
if len(sec.keyList) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count and generate alignment length and buffer spaces using the
|
||||||
|
// longest key. Keys may be modifed if they contain certain characters so
|
||||||
|
// we need to take that into account in our calculation.
|
||||||
|
alignLength := 0
|
||||||
|
if PrettyFormat {
|
||||||
|
for _, kname := range sec.keyList {
|
||||||
|
keyLength := len(kname)
|
||||||
|
// First case will surround key by ` and second by """
|
||||||
|
if strings.ContainsAny(kname, "\"=:") {
|
||||||
|
keyLength += 2
|
||||||
|
} else if strings.Contains(kname, "`") {
|
||||||
|
keyLength += 6
|
||||||
|
}
|
||||||
|
|
||||||
|
if keyLength > alignLength {
|
||||||
|
alignLength = keyLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alignSpaces := bytes.Repeat([]byte(" "), alignLength)
|
||||||
|
|
||||||
|
for _, kname := range sec.keyList {
|
||||||
|
key := sec.Key(kname)
|
||||||
|
if len(key.Comment) > 0 {
|
||||||
|
if len(indent) > 0 && sname != DEFAULT_SECTION {
|
||||||
|
buf.WriteString(indent)
|
||||||
|
}
|
||||||
|
if key.Comment[0] != '#' && key.Comment[0] != ';' {
|
||||||
|
key.Comment = "; " + key.Comment
|
||||||
|
}
|
||||||
|
if _, err = buf.WriteString(key.Comment + LineBreak); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(indent) > 0 && sname != DEFAULT_SECTION {
|
||||||
|
buf.WriteString(indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case key.isAutoIncrement:
|
||||||
|
kname = "-"
|
||||||
|
case strings.ContainsAny(kname, "\"=:"):
|
||||||
|
kname = "`" + kname + "`"
|
||||||
|
case strings.Contains(kname, "`"):
|
||||||
|
kname = `"""` + kname + `"""`
|
||||||
|
}
|
||||||
|
if _, err = buf.WriteString(kname); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if key.isBooleanType {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write out alignment spaces before "=" sign
|
||||||
|
if PrettyFormat {
|
||||||
|
buf.Write(alignSpaces[:alignLength-len(kname)])
|
||||||
|
}
|
||||||
|
|
||||||
|
val := key.value
|
||||||
|
// In case key value contains "\n", "`", "\"", "#" or ";"
|
||||||
|
if strings.ContainsAny(val, "\n`") {
|
||||||
|
val = `"""` + val + `"""`
|
||||||
|
} else if strings.ContainsAny(val, "#;") {
|
||||||
|
val = "`" + val + "`"
|
||||||
|
}
|
||||||
|
if _, err = buf.WriteString(equalSign + val + LineBreak); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put a line between sections
|
||||||
|
if _, err = buf.WriteString(LineBreak); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.WriteTo(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteTo writes file content into io.Writer.
|
||||||
|
func (f *File) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
return f.WriteToIndent(w, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveToIndent writes content to file system with given value indention.
|
||||||
|
func (f *File) SaveToIndent(filename, indent string) error {
|
||||||
|
// Note: Because we are truncating with os.Create,
|
||||||
|
// so it's safer to save to a temporary file location and rename afte done.
|
||||||
|
tmpPath := filename + "." + strconv.Itoa(time.Now().Nanosecond()) + ".tmp"
|
||||||
|
defer os.Remove(tmpPath)
|
||||||
|
|
||||||
|
fw, err := os.Create(tmpPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = f.WriteToIndent(fw, indent); err != nil {
|
||||||
|
fw.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fw.Close()
|
||||||
|
|
||||||
|
// Remove old file and rename the new one.
|
||||||
|
os.Remove(filename)
|
||||||
|
return os.Rename(tmpPath, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveTo writes content to file system.
|
||||||
|
func (f *File) SaveTo(filename string) error {
|
||||||
|
return f.SaveToIndent(filename, "")
|
||||||
|
}
|
633
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/key.go
generated
vendored
Normal file
633
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/key.go
generated
vendored
Normal file
|
@ -0,0 +1,633 @@
|
||||||
|
// Copyright 2014 Unknwon
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package ini
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Key represents a key under a section.
|
||||||
|
type Key struct {
|
||||||
|
s *Section
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
isAutoIncrement bool
|
||||||
|
isBooleanType bool
|
||||||
|
|
||||||
|
Comment string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValueMapper represents a mapping function for values, e.g. os.ExpandEnv
|
||||||
|
type ValueMapper func(string) string
|
||||||
|
|
||||||
|
// Name returns name of key.
|
||||||
|
func (k *Key) Name() string {
|
||||||
|
return k.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns raw value of key for performance purpose.
|
||||||
|
func (k *Key) Value() string {
|
||||||
|
return k.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns string representation of value.
|
||||||
|
func (k *Key) String() string {
|
||||||
|
val := k.value
|
||||||
|
if k.s.f.ValueMapper != nil {
|
||||||
|
val = k.s.f.ValueMapper(val)
|
||||||
|
}
|
||||||
|
if strings.Index(val, "%") == -1 {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < _DEPTH_VALUES; i++ {
|
||||||
|
vr := varPattern.FindString(val)
|
||||||
|
if len(vr) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take off leading '%(' and trailing ')s'.
|
||||||
|
noption := strings.TrimLeft(vr, "%(")
|
||||||
|
noption = strings.TrimRight(noption, ")s")
|
||||||
|
|
||||||
|
// Search in the same section.
|
||||||
|
nk, err := k.s.GetKey(noption)
|
||||||
|
if err != nil {
|
||||||
|
// Search again in default section.
|
||||||
|
nk, _ = k.s.f.Section("").GetKey(noption)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Substitute by new value and take off leading '%(' and trailing ')s'.
|
||||||
|
val = strings.Replace(val, vr, nk.value, -1)
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate accepts a validate function which can
|
||||||
|
// return modifed result as key value.
|
||||||
|
func (k *Key) Validate(fn func(string) string) string {
|
||||||
|
return fn(k.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseBool returns the boolean value represented by the string.
|
||||||
|
//
|
||||||
|
// It accepts 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On,
|
||||||
|
// 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off.
|
||||||
|
// Any other value returns an error.
|
||||||
|
func parseBool(str string) (value bool, err error) {
|
||||||
|
switch str {
|
||||||
|
case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "y", "ON", "on", "On":
|
||||||
|
return true, nil
|
||||||
|
case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "n", "OFF", "off", "Off":
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("parsing \"%s\": invalid syntax", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool returns bool type value.
|
||||||
|
func (k *Key) Bool() (bool, error) {
|
||||||
|
return parseBool(k.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 returns float64 type value.
|
||||||
|
func (k *Key) Float64() (float64, error) {
|
||||||
|
return strconv.ParseFloat(k.String(), 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int returns int type value.
|
||||||
|
func (k *Key) Int() (int, error) {
|
||||||
|
return strconv.Atoi(k.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 returns int64 type value.
|
||||||
|
func (k *Key) Int64() (int64, error) {
|
||||||
|
return strconv.ParseInt(k.String(), 10, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint returns uint type valued.
|
||||||
|
func (k *Key) Uint() (uint, error) {
|
||||||
|
u, e := strconv.ParseUint(k.String(), 10, 64)
|
||||||
|
return uint(u), e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64 returns uint64 type value.
|
||||||
|
func (k *Key) Uint64() (uint64, error) {
|
||||||
|
return strconv.ParseUint(k.String(), 10, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duration returns time.Duration type value.
|
||||||
|
func (k *Key) Duration() (time.Duration, error) {
|
||||||
|
return time.ParseDuration(k.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeFormat parses with given format and returns time.Time type value.
|
||||||
|
func (k *Key) TimeFormat(format string) (time.Time, error) {
|
||||||
|
return time.Parse(format, k.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time parses with RFC3339 format and returns time.Time type value.
|
||||||
|
func (k *Key) Time() (time.Time, error) {
|
||||||
|
return k.TimeFormat(time.RFC3339)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustString returns default value if key value is empty.
|
||||||
|
func (k *Key) MustString(defaultVal string) string {
|
||||||
|
val := k.String()
|
||||||
|
if len(val) == 0 {
|
||||||
|
k.value = defaultVal
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustBool always returns value without error,
|
||||||
|
// it returns false if error occurs.
|
||||||
|
func (k *Key) MustBool(defaultVal ...bool) bool {
|
||||||
|
val, err := k.Bool()
|
||||||
|
if len(defaultVal) > 0 && err != nil {
|
||||||
|
k.value = strconv.FormatBool(defaultVal[0])
|
||||||
|
return defaultVal[0]
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustFloat64 always returns value without error,
|
||||||
|
// it returns 0.0 if error occurs.
|
||||||
|
func (k *Key) MustFloat64(defaultVal ...float64) float64 {
|
||||||
|
val, err := k.Float64()
|
||||||
|
if len(defaultVal) > 0 && err != nil {
|
||||||
|
k.value = strconv.FormatFloat(defaultVal[0], 'f', -1, 64)
|
||||||
|
return defaultVal[0]
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustInt always returns value without error,
|
||||||
|
// it returns 0 if error occurs.
|
||||||
|
func (k *Key) MustInt(defaultVal ...int) int {
|
||||||
|
val, err := k.Int()
|
||||||
|
if len(defaultVal) > 0 && err != nil {
|
||||||
|
k.value = strconv.FormatInt(int64(defaultVal[0]), 10)
|
||||||
|
return defaultVal[0]
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustInt64 always returns value without error,
|
||||||
|
// it returns 0 if error occurs.
|
||||||
|
func (k *Key) MustInt64(defaultVal ...int64) int64 {
|
||||||
|
val, err := k.Int64()
|
||||||
|
if len(defaultVal) > 0 && err != nil {
|
||||||
|
k.value = strconv.FormatInt(defaultVal[0], 10)
|
||||||
|
return defaultVal[0]
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustUint always returns value without error,
|
||||||
|
// it returns 0 if error occurs.
|
||||||
|
func (k *Key) MustUint(defaultVal ...uint) uint {
|
||||||
|
val, err := k.Uint()
|
||||||
|
if len(defaultVal) > 0 && err != nil {
|
||||||
|
k.value = strconv.FormatUint(uint64(defaultVal[0]), 10)
|
||||||
|
return defaultVal[0]
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustUint64 always returns value without error,
|
||||||
|
// it returns 0 if error occurs.
|
||||||
|
func (k *Key) MustUint64(defaultVal ...uint64) uint64 {
|
||||||
|
val, err := k.Uint64()
|
||||||
|
if len(defaultVal) > 0 && err != nil {
|
||||||
|
k.value = strconv.FormatUint(defaultVal[0], 10)
|
||||||
|
return defaultVal[0]
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustDuration always returns value without error,
|
||||||
|
// it returns zero value if error occurs.
|
||||||
|
func (k *Key) MustDuration(defaultVal ...time.Duration) time.Duration {
|
||||||
|
val, err := k.Duration()
|
||||||
|
if len(defaultVal) > 0 && err != nil {
|
||||||
|
k.value = defaultVal[0].String()
|
||||||
|
return defaultVal[0]
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustTimeFormat always parses with given format and returns value without error,
|
||||||
|
// it returns zero value if error occurs.
|
||||||
|
func (k *Key) MustTimeFormat(format string, defaultVal ...time.Time) time.Time {
|
||||||
|
val, err := k.TimeFormat(format)
|
||||||
|
if len(defaultVal) > 0 && err != nil {
|
||||||
|
k.value = defaultVal[0].Format(format)
|
||||||
|
return defaultVal[0]
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustTime always parses with RFC3339 format and returns value without error,
|
||||||
|
// it returns zero value if error occurs.
|
||||||
|
func (k *Key) MustTime(defaultVal ...time.Time) time.Time {
|
||||||
|
return k.MustTimeFormat(time.RFC3339, defaultVal...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// In always returns value without error,
|
||||||
|
// it returns default value if error occurs or doesn't fit into candidates.
|
||||||
|
func (k *Key) In(defaultVal string, candidates []string) string {
|
||||||
|
val := k.String()
|
||||||
|
for _, cand := range candidates {
|
||||||
|
if val == cand {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// InFloat64 always returns value without error,
|
||||||
|
// it returns default value if error occurs or doesn't fit into candidates.
|
||||||
|
func (k *Key) InFloat64(defaultVal float64, candidates []float64) float64 {
|
||||||
|
val := k.MustFloat64()
|
||||||
|
for _, cand := range candidates {
|
||||||
|
if val == cand {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// InInt always returns value without error,
|
||||||
|
// it returns default value if error occurs or doesn't fit into candidates.
|
||||||
|
func (k *Key) InInt(defaultVal int, candidates []int) int {
|
||||||
|
val := k.MustInt()
|
||||||
|
for _, cand := range candidates {
|
||||||
|
if val == cand {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// InInt64 always returns value without error,
|
||||||
|
// it returns default value if error occurs or doesn't fit into candidates.
|
||||||
|
func (k *Key) InInt64(defaultVal int64, candidates []int64) int64 {
|
||||||
|
val := k.MustInt64()
|
||||||
|
for _, cand := range candidates {
|
||||||
|
if val == cand {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// InUint always returns value without error,
|
||||||
|
// it returns default value if error occurs or doesn't fit into candidates.
|
||||||
|
func (k *Key) InUint(defaultVal uint, candidates []uint) uint {
|
||||||
|
val := k.MustUint()
|
||||||
|
for _, cand := range candidates {
|
||||||
|
if val == cand {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// InUint64 always returns value without error,
|
||||||
|
// it returns default value if error occurs or doesn't fit into candidates.
|
||||||
|
func (k *Key) InUint64(defaultVal uint64, candidates []uint64) uint64 {
|
||||||
|
val := k.MustUint64()
|
||||||
|
for _, cand := range candidates {
|
||||||
|
if val == cand {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// InTimeFormat always parses with given format and returns value without error,
|
||||||
|
// it returns default value if error occurs or doesn't fit into candidates.
|
||||||
|
func (k *Key) InTimeFormat(format string, defaultVal time.Time, candidates []time.Time) time.Time {
|
||||||
|
val := k.MustTimeFormat(format)
|
||||||
|
for _, cand := range candidates {
|
||||||
|
if val == cand {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// InTime always parses with RFC3339 format and returns value without error,
|
||||||
|
// it returns default value if error occurs or doesn't fit into candidates.
|
||||||
|
func (k *Key) InTime(defaultVal time.Time, candidates []time.Time) time.Time {
|
||||||
|
return k.InTimeFormat(time.RFC3339, defaultVal, candidates)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RangeFloat64 checks if value is in given range inclusively,
|
||||||
|
// and returns default value if it's not.
|
||||||
|
func (k *Key) RangeFloat64(defaultVal, min, max float64) float64 {
|
||||||
|
val := k.MustFloat64()
|
||||||
|
if val < min || val > max {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// RangeInt checks if value is in given range inclusively,
|
||||||
|
// and returns default value if it's not.
|
||||||
|
func (k *Key) RangeInt(defaultVal, min, max int) int {
|
||||||
|
val := k.MustInt()
|
||||||
|
if val < min || val > max {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// RangeInt64 checks if value is in given range inclusively,
|
||||||
|
// and returns default value if it's not.
|
||||||
|
func (k *Key) RangeInt64(defaultVal, min, max int64) int64 {
|
||||||
|
val := k.MustInt64()
|
||||||
|
if val < min || val > max {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// RangeTimeFormat checks if value with given format is in given range inclusively,
|
||||||
|
// and returns default value if it's not.
|
||||||
|
func (k *Key) RangeTimeFormat(format string, defaultVal, min, max time.Time) time.Time {
|
||||||
|
val := k.MustTimeFormat(format)
|
||||||
|
if val.Unix() < min.Unix() || val.Unix() > max.Unix() {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// RangeTime checks if value with RFC3339 format is in given range inclusively,
|
||||||
|
// and returns default value if it's not.
|
||||||
|
func (k *Key) RangeTime(defaultVal, min, max time.Time) time.Time {
|
||||||
|
return k.RangeTimeFormat(time.RFC3339, defaultVal, min, max)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strings returns list of string divided by given delimiter.
|
||||||
|
func (k *Key) Strings(delim string) []string {
|
||||||
|
str := k.String()
|
||||||
|
if len(str) == 0 {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
vals := strings.Split(str, delim)
|
||||||
|
for i := range vals {
|
||||||
|
vals[i] = strings.TrimSpace(vals[i])
|
||||||
|
}
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value.
|
||||||
|
func (k *Key) Float64s(delim string) []float64 {
|
||||||
|
vals, _ := k.getFloat64s(delim, true, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value.
|
||||||
|
func (k *Key) Ints(delim string) []int {
|
||||||
|
vals, _ := k.getInts(delim, true, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value.
|
||||||
|
func (k *Key) Int64s(delim string) []int64 {
|
||||||
|
vals, _ := k.getInt64s(delim, true, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value.
|
||||||
|
func (k *Key) Uints(delim string) []uint {
|
||||||
|
vals, _ := k.getUints(delim, true, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value.
|
||||||
|
func (k *Key) Uint64s(delim string) []uint64 {
|
||||||
|
vals, _ := k.getUint64s(delim, true, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimesFormat parses with given format and returns list of time.Time divided by given delimiter.
|
||||||
|
// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC).
|
||||||
|
func (k *Key) TimesFormat(format, delim string) []time.Time {
|
||||||
|
vals, _ := k.getTimesFormat(format, delim, true, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// Times parses with RFC3339 format and returns list of time.Time divided by given delimiter.
|
||||||
|
// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC).
|
||||||
|
func (k *Key) Times(delim string) []time.Time {
|
||||||
|
return k.TimesFormat(time.RFC3339, delim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then
|
||||||
|
// it will not be included to result list.
|
||||||
|
func (k *Key) ValidFloat64s(delim string) []float64 {
|
||||||
|
vals, _ := k.getFloat64s(delim, false, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will
|
||||||
|
// not be included to result list.
|
||||||
|
func (k *Key) ValidInts(delim string) []int {
|
||||||
|
vals, _ := k.getInts(delim, false, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer,
|
||||||
|
// then it will not be included to result list.
|
||||||
|
func (k *Key) ValidInt64s(delim string) []int64 {
|
||||||
|
vals, _ := k.getInt64s(delim, false, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer,
|
||||||
|
// then it will not be included to result list.
|
||||||
|
func (k *Key) ValidUints(delim string) []uint {
|
||||||
|
vals, _ := k.getUints(delim, false, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned
|
||||||
|
// integer, then it will not be included to result list.
|
||||||
|
func (k *Key) ValidUint64s(delim string) []uint64 {
|
||||||
|
vals, _ := k.getUint64s(delim, false, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter.
|
||||||
|
func (k *Key) ValidTimesFormat(format, delim string) []time.Time {
|
||||||
|
vals, _ := k.getTimesFormat(format, delim, false, false)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter.
|
||||||
|
func (k *Key) ValidTimes(delim string) []time.Time {
|
||||||
|
return k.ValidTimesFormat(time.RFC3339, delim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input.
|
||||||
|
func (k *Key) StrictFloat64s(delim string) ([]float64, error) {
|
||||||
|
return k.getFloat64s(delim, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrictInts returns list of int divided by given delimiter or error on first invalid input.
|
||||||
|
func (k *Key) StrictInts(delim string) ([]int, error) {
|
||||||
|
return k.getInts(delim, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input.
|
||||||
|
func (k *Key) StrictInt64s(delim string) ([]int64, error) {
|
||||||
|
return k.getInt64s(delim, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrictUints returns list of uint divided by given delimiter or error on first invalid input.
|
||||||
|
func (k *Key) StrictUints(delim string) ([]uint, error) {
|
||||||
|
return k.getUints(delim, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input.
|
||||||
|
func (k *Key) StrictUint64s(delim string) ([]uint64, error) {
|
||||||
|
return k.getUint64s(delim, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter
|
||||||
|
// or error on first invalid input.
|
||||||
|
func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) {
|
||||||
|
return k.getTimesFormat(format, delim, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter
|
||||||
|
// or error on first invalid input.
|
||||||
|
func (k *Key) StrictTimes(delim string) ([]time.Time, error) {
|
||||||
|
return k.StrictTimesFormat(time.RFC3339, delim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getFloat64s returns list of float64 divided by given delimiter.
|
||||||
|
func (k *Key) getFloat64s(delim string, addInvalid, returnOnInvalid bool) ([]float64, error) {
|
||||||
|
strs := k.Strings(delim)
|
||||||
|
vals := make([]float64, 0, len(strs))
|
||||||
|
for _, str := range strs {
|
||||||
|
val, err := strconv.ParseFloat(str, 64)
|
||||||
|
if err != nil && returnOnInvalid {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err == nil || addInvalid {
|
||||||
|
vals = append(vals, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getInts returns list of int divided by given delimiter.
|
||||||
|
func (k *Key) getInts(delim string, addInvalid, returnOnInvalid bool) ([]int, error) {
|
||||||
|
strs := k.Strings(delim)
|
||||||
|
vals := make([]int, 0, len(strs))
|
||||||
|
for _, str := range strs {
|
||||||
|
val, err := strconv.Atoi(str)
|
||||||
|
if err != nil && returnOnInvalid {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err == nil || addInvalid {
|
||||||
|
vals = append(vals, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getInt64s returns list of int64 divided by given delimiter.
|
||||||
|
func (k *Key) getInt64s(delim string, addInvalid, returnOnInvalid bool) ([]int64, error) {
|
||||||
|
strs := k.Strings(delim)
|
||||||
|
vals := make([]int64, 0, len(strs))
|
||||||
|
for _, str := range strs {
|
||||||
|
val, err := strconv.ParseInt(str, 10, 64)
|
||||||
|
if err != nil && returnOnInvalid {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err == nil || addInvalid {
|
||||||
|
vals = append(vals, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getUints returns list of uint divided by given delimiter.
|
||||||
|
func (k *Key) getUints(delim string, addInvalid, returnOnInvalid bool) ([]uint, error) {
|
||||||
|
strs := k.Strings(delim)
|
||||||
|
vals := make([]uint, 0, len(strs))
|
||||||
|
for _, str := range strs {
|
||||||
|
val, err := strconv.ParseUint(str, 10, 0)
|
||||||
|
if err != nil && returnOnInvalid {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err == nil || addInvalid {
|
||||||
|
vals = append(vals, uint(val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getUint64s returns list of uint64 divided by given delimiter.
|
||||||
|
func (k *Key) getUint64s(delim string, addInvalid, returnOnInvalid bool) ([]uint64, error) {
|
||||||
|
strs := k.Strings(delim)
|
||||||
|
vals := make([]uint64, 0, len(strs))
|
||||||
|
for _, str := range strs {
|
||||||
|
val, err := strconv.ParseUint(str, 10, 64)
|
||||||
|
if err != nil && returnOnInvalid {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err == nil || addInvalid {
|
||||||
|
vals = append(vals, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTimesFormat parses with given format and returns list of time.Time divided by given delimiter.
|
||||||
|
func (k *Key) getTimesFormat(format, delim string, addInvalid, returnOnInvalid bool) ([]time.Time, error) {
|
||||||
|
strs := k.Strings(delim)
|
||||||
|
vals := make([]time.Time, 0, len(strs))
|
||||||
|
for _, str := range strs {
|
||||||
|
val, err := time.Parse(format, str)
|
||||||
|
if err != nil && returnOnInvalid {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err == nil || addInvalid {
|
||||||
|
vals = append(vals, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValue changes key value.
|
||||||
|
func (k *Key) SetValue(v string) {
|
||||||
|
if k.s.f.BlockMode {
|
||||||
|
k.s.f.lock.Lock()
|
||||||
|
defer k.s.f.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
k.value = v
|
||||||
|
k.s.keysHash[k.name] = v
|
||||||
|
}
|
325
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/parser.go
generated
vendored
Normal file
325
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/parser.go
generated
vendored
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
// Copyright 2015 Unknwon
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package ini
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tokenType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
_TOKEN_INVALID tokenType = iota
|
||||||
|
_TOKEN_COMMENT
|
||||||
|
_TOKEN_SECTION
|
||||||
|
_TOKEN_KEY
|
||||||
|
)
|
||||||
|
|
||||||
|
type parser struct {
|
||||||
|
buf *bufio.Reader
|
||||||
|
isEOF bool
|
||||||
|
count int
|
||||||
|
comment *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParser(r io.Reader) *parser {
|
||||||
|
return &parser{
|
||||||
|
buf: bufio.NewReader(r),
|
||||||
|
count: 1,
|
||||||
|
comment: &bytes.Buffer{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BOM handles header of BOM-UTF8 format.
|
||||||
|
// http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding
|
||||||
|
func (p *parser) BOM() error {
|
||||||
|
mask, err := p.buf.Peek(3)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
} else if len(mask) < 3 {
|
||||||
|
return nil
|
||||||
|
} else if mask[0] == 239 && mask[1] == 187 && mask[2] == 191 {
|
||||||
|
p.buf.Read(mask)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) readUntil(delim byte) ([]byte, error) {
|
||||||
|
data, err := p.buf.ReadBytes(delim)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
p.isEOF = true
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanComment(in []byte) ([]byte, bool) {
|
||||||
|
i := bytes.IndexAny(in, "#;")
|
||||||
|
if i == -1 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return in[i:], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func readKeyName(in []byte) (string, int, error) {
|
||||||
|
line := string(in)
|
||||||
|
|
||||||
|
// Check if key name surrounded by quotes.
|
||||||
|
var keyQuote string
|
||||||
|
if line[0] == '"' {
|
||||||
|
if len(line) > 6 && string(line[0:3]) == `"""` {
|
||||||
|
keyQuote = `"""`
|
||||||
|
} else {
|
||||||
|
keyQuote = `"`
|
||||||
|
}
|
||||||
|
} else if line[0] == '`' {
|
||||||
|
keyQuote = "`"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get out key name
|
||||||
|
endIdx := -1
|
||||||
|
if len(keyQuote) > 0 {
|
||||||
|
startIdx := len(keyQuote)
|
||||||
|
// FIXME: fail case -> """"""name"""=value
|
||||||
|
pos := strings.Index(line[startIdx:], keyQuote)
|
||||||
|
if pos == -1 {
|
||||||
|
return "", -1, fmt.Errorf("missing closing key quote: %s", line)
|
||||||
|
}
|
||||||
|
pos += startIdx
|
||||||
|
|
||||||
|
// Find key-value delimiter
|
||||||
|
i := strings.IndexAny(line[pos+startIdx:], "=:")
|
||||||
|
if i < 0 {
|
||||||
|
return "", -1, ErrDelimiterNotFound{line}
|
||||||
|
}
|
||||||
|
endIdx = pos + i
|
||||||
|
return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
endIdx = strings.IndexAny(line, "=:")
|
||||||
|
if endIdx < 0 {
|
||||||
|
return "", -1, ErrDelimiterNotFound{line}
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(line[0:endIdx]), endIdx + 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) readMultilines(line, val, valQuote string) (string, error) {
|
||||||
|
for {
|
||||||
|
data, err := p.readUntil('\n')
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
next := string(data)
|
||||||
|
|
||||||
|
pos := strings.LastIndex(next, valQuote)
|
||||||
|
if pos > -1 {
|
||||||
|
val += next[:pos]
|
||||||
|
|
||||||
|
comment, has := cleanComment([]byte(next[pos:]))
|
||||||
|
if has {
|
||||||
|
p.comment.Write(bytes.TrimSpace(comment))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
val += next
|
||||||
|
if p.isEOF {
|
||||||
|
return "", fmt.Errorf("missing closing key quote from '%s' to '%s'", line, next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) readContinuationLines(val string) (string, error) {
|
||||||
|
for {
|
||||||
|
data, err := p.readUntil('\n')
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
next := strings.TrimSpace(string(data))
|
||||||
|
|
||||||
|
if len(next) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
val += next
|
||||||
|
if val[len(val)-1] != '\\' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
val = val[:len(val)-1]
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasSurroundedQuote check if and only if the first and last characters
|
||||||
|
// are quotes \" or \'.
|
||||||
|
// It returns false if any other parts also contain same kind of quotes.
|
||||||
|
func hasSurroundedQuote(in string, quote byte) bool {
|
||||||
|
return len(in) > 2 && in[0] == quote && in[len(in)-1] == quote &&
|
||||||
|
strings.IndexByte(in[1:], quote) == len(in)-2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) readValue(in []byte, ignoreContinuation bool) (string, error) {
|
||||||
|
line := strings.TrimLeftFunc(string(in), unicode.IsSpace)
|
||||||
|
if len(line) == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var valQuote string
|
||||||
|
if len(line) > 3 && string(line[0:3]) == `"""` {
|
||||||
|
valQuote = `"""`
|
||||||
|
} else if line[0] == '`' {
|
||||||
|
valQuote = "`"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(valQuote) > 0 {
|
||||||
|
startIdx := len(valQuote)
|
||||||
|
pos := strings.LastIndex(line[startIdx:], valQuote)
|
||||||
|
// Check for multi-line value
|
||||||
|
if pos == -1 {
|
||||||
|
return p.readMultilines(line, line[startIdx:], valQuote)
|
||||||
|
}
|
||||||
|
|
||||||
|
return line[startIdx : pos+startIdx], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Won't be able to reach here if value only contains whitespace.
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
// Check continuation lines when desired.
|
||||||
|
if !ignoreContinuation && line[len(line)-1] == '\\' {
|
||||||
|
return p.readContinuationLines(line[:len(line)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
i := strings.IndexAny(line, "#;")
|
||||||
|
if i > -1 {
|
||||||
|
p.comment.WriteString(line[i:])
|
||||||
|
line = strings.TrimSpace(line[:i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim single quotes
|
||||||
|
if hasSurroundedQuote(line, '\'') ||
|
||||||
|
hasSurroundedQuote(line, '"') {
|
||||||
|
line = line[1 : len(line)-1]
|
||||||
|
}
|
||||||
|
return line, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse parses data through an io.Reader.
|
||||||
|
func (f *File) parse(reader io.Reader) (err error) {
|
||||||
|
p := newParser(reader)
|
||||||
|
if err = p.BOM(); err != nil {
|
||||||
|
return fmt.Errorf("BOM: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore error because default section name is never empty string.
|
||||||
|
section, _ := f.NewSection(DEFAULT_SECTION)
|
||||||
|
|
||||||
|
var line []byte
|
||||||
|
for !p.isEOF {
|
||||||
|
line, err = p.readUntil('\n')
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
line = bytes.TrimLeftFunc(line, unicode.IsSpace)
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
if line[0] == '#' || line[0] == ';' {
|
||||||
|
// Note: we do not care ending line break,
|
||||||
|
// it is needed for adding second line,
|
||||||
|
// so just clean it once at the end when set to value.
|
||||||
|
p.comment.Write(line)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section
|
||||||
|
if line[0] == '[' {
|
||||||
|
// Read to the next ']' (TODO: support quoted strings)
|
||||||
|
// TODO(unknwon): use LastIndexByte when stop supporting Go1.4
|
||||||
|
closeIdx := bytes.LastIndex(line, []byte("]"))
|
||||||
|
if closeIdx == -1 {
|
||||||
|
return fmt.Errorf("unclosed section: %s", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := string(line[1:closeIdx])
|
||||||
|
section, err = f.NewSection(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
comment, has := cleanComment(line[closeIdx+1:])
|
||||||
|
if has {
|
||||||
|
p.comment.Write(comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
section.Comment = strings.TrimSpace(p.comment.String())
|
||||||
|
|
||||||
|
// Reset aotu-counter and comments
|
||||||
|
p.comment.Reset()
|
||||||
|
p.count = 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
kname, offset, err := readKeyName(line)
|
||||||
|
if err != nil {
|
||||||
|
// Treat as boolean key when desired, and whole line is key name.
|
||||||
|
if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys {
|
||||||
|
key, err := section.NewKey(string(line), "true")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
key.isBooleanType = true
|
||||||
|
key.Comment = strings.TrimSpace(p.comment.String())
|
||||||
|
p.comment.Reset()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto increment.
|
||||||
|
isAutoIncr := false
|
||||||
|
if kname == "-" {
|
||||||
|
isAutoIncr = true
|
||||||
|
kname = "#" + strconv.Itoa(p.count)
|
||||||
|
p.count++
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := section.NewKey(kname, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
key.isAutoIncrement = isAutoIncr
|
||||||
|
|
||||||
|
value, err := p.readValue(line[offset:], f.options.IgnoreContinuation)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
key.SetValue(value)
|
||||||
|
key.Comment = strings.TrimSpace(p.comment.String())
|
||||||
|
p.comment.Reset()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
206
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/section.go
generated
vendored
Normal file
206
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/section.go
generated
vendored
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
// Copyright 2014 Unknwon
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package ini
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Section represents a config section.
|
||||||
|
type Section struct {
|
||||||
|
f *File
|
||||||
|
Comment string
|
||||||
|
name string
|
||||||
|
keys map[string]*Key
|
||||||
|
keyList []string
|
||||||
|
keysHash map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSection(f *File, name string) *Section {
|
||||||
|
return &Section{f, "", name, make(map[string]*Key), make([]string, 0, 10), make(map[string]string)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns name of Section.
|
||||||
|
func (s *Section) Name() string {
|
||||||
|
return s.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewKey creates a new key to given section.
|
||||||
|
func (s *Section) NewKey(name, val string) (*Key, error) {
|
||||||
|
if len(name) == 0 {
|
||||||
|
return nil, errors.New("error creating new key: empty key name")
|
||||||
|
} else if s.f.options.Insensitive {
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.f.BlockMode {
|
||||||
|
s.f.lock.Lock()
|
||||||
|
defer s.f.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if inSlice(name, s.keyList) {
|
||||||
|
s.keys[name].value = val
|
||||||
|
return s.keys[name], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s.keyList = append(s.keyList, name)
|
||||||
|
s.keys[name] = &Key{
|
||||||
|
s: s,
|
||||||
|
name: name,
|
||||||
|
value: val,
|
||||||
|
}
|
||||||
|
s.keysHash[name] = val
|
||||||
|
return s.keys[name], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKey returns key in section by given name.
|
||||||
|
func (s *Section) GetKey(name string) (*Key, error) {
|
||||||
|
// FIXME: change to section level lock?
|
||||||
|
if s.f.BlockMode {
|
||||||
|
s.f.lock.RLock()
|
||||||
|
}
|
||||||
|
if s.f.options.Insensitive {
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
}
|
||||||
|
key := s.keys[name]
|
||||||
|
if s.f.BlockMode {
|
||||||
|
s.f.lock.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == nil {
|
||||||
|
// Check if it is a child-section.
|
||||||
|
sname := s.name
|
||||||
|
for {
|
||||||
|
if i := strings.LastIndex(sname, "."); i > -1 {
|
||||||
|
sname = sname[:i]
|
||||||
|
sec, err := s.f.GetSection(sname)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return sec.GetKey(name)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("error when getting key of section '%s': key '%s' not exists", s.name, name)
|
||||||
|
}
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasKey returns true if section contains a key with given name.
|
||||||
|
func (s *Section) HasKey(name string) bool {
|
||||||
|
key, _ := s.GetKey(name)
|
||||||
|
return key != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Haskey is a backwards-compatible name for HasKey.
|
||||||
|
func (s *Section) Haskey(name string) bool {
|
||||||
|
return s.HasKey(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasValue returns true if section contains given raw value.
|
||||||
|
func (s *Section) HasValue(value string) bool {
|
||||||
|
if s.f.BlockMode {
|
||||||
|
s.f.lock.RLock()
|
||||||
|
defer s.f.lock.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range s.keys {
|
||||||
|
if value == k.value {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key assumes named Key exists in section and returns a zero-value when not.
|
||||||
|
func (s *Section) Key(name string) *Key {
|
||||||
|
key, err := s.GetKey(name)
|
||||||
|
if err != nil {
|
||||||
|
// It's OK here because the only possible error is empty key name,
|
||||||
|
// but if it's empty, this piece of code won't be executed.
|
||||||
|
key, _ = s.NewKey(name, "")
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys returns list of keys of section.
|
||||||
|
func (s *Section) Keys() []*Key {
|
||||||
|
keys := make([]*Key, len(s.keyList))
|
||||||
|
for i := range s.keyList {
|
||||||
|
keys[i] = s.Key(s.keyList[i])
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParentKeys returns list of keys of parent section.
|
||||||
|
func (s *Section) ParentKeys() []*Key {
|
||||||
|
var parentKeys []*Key
|
||||||
|
sname := s.name
|
||||||
|
for {
|
||||||
|
if i := strings.LastIndex(sname, "."); i > -1 {
|
||||||
|
sname = sname[:i]
|
||||||
|
sec, err := s.f.GetSection(sname)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parentKeys = append(parentKeys, sec.Keys()...)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return parentKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyStrings returns list of key names of section.
|
||||||
|
func (s *Section) KeyStrings() []string {
|
||||||
|
list := make([]string, len(s.keyList))
|
||||||
|
copy(list, s.keyList)
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeysHash returns keys hash consisting of names and values.
|
||||||
|
func (s *Section) KeysHash() map[string]string {
|
||||||
|
if s.f.BlockMode {
|
||||||
|
s.f.lock.RLock()
|
||||||
|
defer s.f.lock.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := map[string]string{}
|
||||||
|
for key, value := range s.keysHash {
|
||||||
|
hash[key] = value
|
||||||
|
}
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteKey deletes a key from section.
|
||||||
|
func (s *Section) DeleteKey(name string) {
|
||||||
|
if s.f.BlockMode {
|
||||||
|
s.f.lock.Lock()
|
||||||
|
defer s.f.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, k := range s.keyList {
|
||||||
|
if k == name {
|
||||||
|
s.keyList = append(s.keyList[:i], s.keyList[i+1:]...)
|
||||||
|
delete(s.keys, name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
431
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/struct.go
generated
vendored
Normal file
431
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/go-ini/ini/struct.go
generated
vendored
Normal file
|
@ -0,0 +1,431 @@
|
||||||
|
// Copyright 2014 Unknwon
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package ini
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NameMapper represents a ini tag name mapper.
|
||||||
|
type NameMapper func(string) string
|
||||||
|
|
||||||
|
// Built-in name getters.
|
||||||
|
var (
|
||||||
|
// AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE.
|
||||||
|
AllCapsUnderscore NameMapper = func(raw string) string {
|
||||||
|
newstr := make([]rune, 0, len(raw))
|
||||||
|
for i, chr := range raw {
|
||||||
|
if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
|
||||||
|
if i > 0 {
|
||||||
|
newstr = append(newstr, '_')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newstr = append(newstr, unicode.ToUpper(chr))
|
||||||
|
}
|
||||||
|
return string(newstr)
|
||||||
|
}
|
||||||
|
// TitleUnderscore converts to format title_underscore.
|
||||||
|
TitleUnderscore NameMapper = func(raw string) string {
|
||||||
|
newstr := make([]rune, 0, len(raw))
|
||||||
|
for i, chr := range raw {
|
||||||
|
if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
|
||||||
|
if i > 0 {
|
||||||
|
newstr = append(newstr, '_')
|
||||||
|
}
|
||||||
|
chr -= ('A' - 'a')
|
||||||
|
}
|
||||||
|
newstr = append(newstr, chr)
|
||||||
|
}
|
||||||
|
return string(newstr)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Section) parseFieldName(raw, actual string) string {
|
||||||
|
if len(actual) > 0 {
|
||||||
|
return actual
|
||||||
|
}
|
||||||
|
if s.f.NameMapper != nil {
|
||||||
|
return s.f.NameMapper(raw)
|
||||||
|
}
|
||||||
|
return raw
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDelim(actual string) string {
|
||||||
|
if len(actual) > 0 {
|
||||||
|
return actual
|
||||||
|
}
|
||||||
|
return ","
|
||||||
|
}
|
||||||
|
|
||||||
|
var reflectTime = reflect.TypeOf(time.Now()).Kind()
|
||||||
|
|
||||||
|
// setSliceWithProperType sets proper values to slice based on its type.
|
||||||
|
func setSliceWithProperType(key *Key, field reflect.Value, delim string) error {
|
||||||
|
strs := key.Strings(delim)
|
||||||
|
numVals := len(strs)
|
||||||
|
if numVals == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var vals interface{}
|
||||||
|
|
||||||
|
sliceOf := field.Type().Elem().Kind()
|
||||||
|
switch sliceOf {
|
||||||
|
case reflect.String:
|
||||||
|
vals = strs
|
||||||
|
case reflect.Int:
|
||||||
|
vals = key.Ints(delim)
|
||||||
|
case reflect.Int64:
|
||||||
|
vals = key.Int64s(delim)
|
||||||
|
case reflect.Uint:
|
||||||
|
vals = key.Uints(delim)
|
||||||
|
case reflect.Uint64:
|
||||||
|
vals = key.Uint64s(delim)
|
||||||
|
case reflect.Float64:
|
||||||
|
vals = key.Float64s(delim)
|
||||||
|
case reflectTime:
|
||||||
|
vals = key.Times(delim)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported type '[]%s'", sliceOf)
|
||||||
|
}
|
||||||
|
|
||||||
|
slice := reflect.MakeSlice(field.Type(), numVals, numVals)
|
||||||
|
for i := 0; i < numVals; i++ {
|
||||||
|
switch sliceOf {
|
||||||
|
case reflect.String:
|
||||||
|
slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i]))
|
||||||
|
case reflect.Int:
|
||||||
|
slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i]))
|
||||||
|
case reflect.Int64:
|
||||||
|
slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i]))
|
||||||
|
case reflect.Uint:
|
||||||
|
slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i]))
|
||||||
|
case reflect.Uint64:
|
||||||
|
slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i]))
|
||||||
|
case reflect.Float64:
|
||||||
|
slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i]))
|
||||||
|
case reflectTime:
|
||||||
|
slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
field.Set(slice)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setWithProperType sets proper value to field based on its type,
|
||||||
|
// but it does not return error for failing parsing,
|
||||||
|
// because we want to use default value that is already assigned to strcut.
|
||||||
|
func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error {
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
if len(key.String()) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
field.SetString(key.String())
|
||||||
|
case reflect.Bool:
|
||||||
|
boolVal, err := key.Bool()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
field.SetBool(boolVal)
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
durationVal, err := key.Duration()
|
||||||
|
// Skip zero value
|
||||||
|
if err == nil && int(durationVal) > 0 {
|
||||||
|
field.Set(reflect.ValueOf(durationVal))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
intVal, err := key.Int64()
|
||||||
|
if err != nil || intVal == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
field.SetInt(intVal)
|
||||||
|
// byte is an alias for uint8, so supporting uint8 breaks support for byte
|
||||||
|
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
durationVal, err := key.Duration()
|
||||||
|
// Skip zero value
|
||||||
|
if err == nil && int(durationVal) > 0 {
|
||||||
|
field.Set(reflect.ValueOf(durationVal))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
uintVal, err := key.Uint64()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
field.SetUint(uintVal)
|
||||||
|
|
||||||
|
case reflect.Float64:
|
||||||
|
floatVal, err := key.Float64()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
field.SetFloat(floatVal)
|
||||||
|
case reflectTime:
|
||||||
|
timeVal, err := key.Time()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
field.Set(reflect.ValueOf(timeVal))
|
||||||
|
case reflect.Slice:
|
||||||
|
return setSliceWithProperType(key, field, delim)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported type '%s'", t)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Section) mapTo(val reflect.Value) error {
|
||||||
|
if val.Kind() == reflect.Ptr {
|
||||||
|
val = val.Elem()
|
||||||
|
}
|
||||||
|
typ := val.Type()
|
||||||
|
|
||||||
|
for i := 0; i < typ.NumField(); i++ {
|
||||||
|
field := val.Field(i)
|
||||||
|
tpField := typ.Field(i)
|
||||||
|
|
||||||
|
tag := tpField.Tag.Get("ini")
|
||||||
|
if tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := strings.SplitN(tag, ",", 2) // strip off possible omitempty
|
||||||
|
fieldName := s.parseFieldName(tpField.Name, opts[0])
|
||||||
|
if len(fieldName) == 0 || !field.CanSet() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous
|
||||||
|
isStruct := tpField.Type.Kind() == reflect.Struct
|
||||||
|
if isAnonymous {
|
||||||
|
field.Set(reflect.New(tpField.Type.Elem()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if isAnonymous || isStruct {
|
||||||
|
if sec, err := s.f.GetSection(fieldName); err == nil {
|
||||||
|
if err = sec.mapTo(field); err != nil {
|
||||||
|
return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if key, err := s.GetKey(fieldName); err == nil {
|
||||||
|
if err = setWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
|
||||||
|
return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapTo maps section to given struct.
|
||||||
|
func (s *Section) MapTo(v interface{}) error {
|
||||||
|
typ := reflect.TypeOf(v)
|
||||||
|
val := reflect.ValueOf(v)
|
||||||
|
if typ.Kind() == reflect.Ptr {
|
||||||
|
typ = typ.Elem()
|
||||||
|
val = val.Elem()
|
||||||
|
} else {
|
||||||
|
return errors.New("cannot map to non-pointer struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.mapTo(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapTo maps file to given struct.
|
||||||
|
func (f *File) MapTo(v interface{}) error {
|
||||||
|
return f.Section("").MapTo(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapTo maps data sources to given struct with name mapper.
|
||||||
|
func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
|
||||||
|
cfg, err := Load(source, others...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cfg.NameMapper = mapper
|
||||||
|
return cfg.MapTo(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapTo maps data sources to given struct.
|
||||||
|
func MapTo(v, source interface{}, others ...interface{}) error {
|
||||||
|
return MapToWithMapper(v, nil, source, others...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reflectSliceWithProperType does the opposite thing as setSliceWithProperType.
|
||||||
|
func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) error {
|
||||||
|
slice := field.Slice(0, field.Len())
|
||||||
|
if field.Len() == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
sliceOf := field.Type().Elem().Kind()
|
||||||
|
for i := 0; i < field.Len(); i++ {
|
||||||
|
switch sliceOf {
|
||||||
|
case reflect.String:
|
||||||
|
buf.WriteString(slice.Index(i).String())
|
||||||
|
case reflect.Int, reflect.Int64:
|
||||||
|
buf.WriteString(fmt.Sprint(slice.Index(i).Int()))
|
||||||
|
case reflect.Uint, reflect.Uint64:
|
||||||
|
buf.WriteString(fmt.Sprint(slice.Index(i).Uint()))
|
||||||
|
case reflect.Float64:
|
||||||
|
buf.WriteString(fmt.Sprint(slice.Index(i).Float()))
|
||||||
|
case reflectTime:
|
||||||
|
buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339))
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported type '[]%s'", sliceOf)
|
||||||
|
}
|
||||||
|
buf.WriteString(delim)
|
||||||
|
}
|
||||||
|
key.SetValue(buf.String()[:buf.Len()-1])
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// reflectWithProperType does the opposite thing as setWithProperType.
|
||||||
|
func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error {
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
key.SetValue(field.String())
|
||||||
|
case reflect.Bool:
|
||||||
|
key.SetValue(fmt.Sprint(field.Bool()))
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
key.SetValue(fmt.Sprint(field.Int()))
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
key.SetValue(fmt.Sprint(field.Uint()))
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
key.SetValue(fmt.Sprint(field.Float()))
|
||||||
|
case reflectTime:
|
||||||
|
key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339)))
|
||||||
|
case reflect.Slice:
|
||||||
|
return reflectSliceWithProperType(key, field, delim)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported type '%s'", t)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CR: copied from encoding/json/encode.go with modifications of time.Time support.
|
||||||
|
// TODO: add more test coverage.
|
||||||
|
func isEmptyValue(v reflect.Value) bool {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||||
|
return v.Len() == 0
|
||||||
|
case reflect.Bool:
|
||||||
|
return !v.Bool()
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return v.Int() == 0
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return v.Uint() == 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float() == 0
|
||||||
|
case reflectTime:
|
||||||
|
return v.Interface().(time.Time).IsZero()
|
||||||
|
case reflect.Interface, reflect.Ptr:
|
||||||
|
return v.IsNil()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Section) reflectFrom(val reflect.Value) error {
|
||||||
|
if val.Kind() == reflect.Ptr {
|
||||||
|
val = val.Elem()
|
||||||
|
}
|
||||||
|
typ := val.Type()
|
||||||
|
|
||||||
|
for i := 0; i < typ.NumField(); i++ {
|
||||||
|
field := val.Field(i)
|
||||||
|
tpField := typ.Field(i)
|
||||||
|
|
||||||
|
tag := tpField.Tag.Get("ini")
|
||||||
|
if tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := strings.SplitN(tag, ",", 2)
|
||||||
|
if len(opts) == 2 && opts[1] == "omitempty" && isEmptyValue(field) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldName := s.parseFieldName(tpField.Name, opts[0])
|
||||||
|
if len(fieldName) == 0 || !field.CanSet() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) ||
|
||||||
|
(tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") {
|
||||||
|
// Note: The only error here is section doesn't exist.
|
||||||
|
sec, err := s.f.GetSection(fieldName)
|
||||||
|
if err != nil {
|
||||||
|
// Note: fieldName can never be empty here, ignore error.
|
||||||
|
sec, _ = s.f.NewSection(fieldName)
|
||||||
|
}
|
||||||
|
if err = sec.reflectFrom(field); err != nil {
|
||||||
|
return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: Same reason as secion.
|
||||||
|
key, err := s.GetKey(fieldName)
|
||||||
|
if err != nil {
|
||||||
|
key, _ = s.NewKey(fieldName, "")
|
||||||
|
}
|
||||||
|
if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
|
||||||
|
return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReflectFrom reflects secion from given struct.
|
||||||
|
func (s *Section) ReflectFrom(v interface{}) error {
|
||||||
|
typ := reflect.TypeOf(v)
|
||||||
|
val := reflect.ValueOf(v)
|
||||||
|
if typ.Kind() == reflect.Ptr {
|
||||||
|
typ = typ.Elem()
|
||||||
|
val = val.Elem()
|
||||||
|
} else {
|
||||||
|
return errors.New("cannot reflect from non-pointer struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.reflectFrom(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReflectFrom reflects file from given struct.
|
||||||
|
func (f *File) ReflectFrom(v interface{}) error {
|
||||||
|
return f.Section("").ReflectFrom(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReflectFrom reflects data sources from given struct with name mapper.
|
||||||
|
func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error {
|
||||||
|
cfg.NameMapper = mapper
|
||||||
|
return cfg.ReflectFrom(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReflectFrom reflects data sources from given struct.
|
||||||
|
func ReflectFrom(cfg *File, v interface{}) error {
|
||||||
|
return ReflectFromWithMapper(cfg, v, nil)
|
||||||
|
}
|
13
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/LICENSE
generated
vendored
Normal file
13
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Copyright 2015 James Saryerwinnie
|
||||||
|
|
||||||
|
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.
|
44
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/Makefile
generated
vendored
Normal file
44
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
|
||||||
|
CMD = jpgo
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
|
@echo " test to run all the tests"
|
||||||
|
@echo " build to build the library and jp executable"
|
||||||
|
@echo " generate to run codegen"
|
||||||
|
|
||||||
|
|
||||||
|
generate:
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
build:
|
||||||
|
rm -f $(CMD)
|
||||||
|
go build ./...
|
||||||
|
rm -f cmd/$(CMD)/$(CMD) && cd cmd/$(CMD)/ && go build ./...
|
||||||
|
mv cmd/$(CMD)/$(CMD) .
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test -v ./...
|
||||||
|
|
||||||
|
check:
|
||||||
|
go vet ./...
|
||||||
|
@echo "golint ./..."
|
||||||
|
@lint=`golint ./...`; \
|
||||||
|
lint=`echo "$$lint" | grep -v "astnodetype_string.go" | grep -v "toktype_string.go"`; \
|
||||||
|
echo "$$lint"; \
|
||||||
|
if [ "$$lint" != "" ]; then exit 1; fi
|
||||||
|
|
||||||
|
htmlc:
|
||||||
|
go test -coverprofile="/tmp/jpcov" && go tool cover -html="/tmp/jpcov" && unlink /tmp/jpcov
|
||||||
|
|
||||||
|
buildfuzz:
|
||||||
|
go-fuzz-build github.com/jmespath/go-jmespath/fuzz
|
||||||
|
|
||||||
|
fuzz: buildfuzz
|
||||||
|
go-fuzz -bin=./jmespath-fuzz.zip -workdir=fuzz/testdata
|
||||||
|
|
||||||
|
bench:
|
||||||
|
go test -bench . -cpuprofile cpu.out
|
||||||
|
|
||||||
|
pprof-cpu:
|
||||||
|
go tool pprof ./go-jmespath.test ./cpu.out
|
7
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/README.md
generated
vendored
Normal file
7
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/README.md
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# go-jmespath - A JMESPath implementation in Go
|
||||||
|
|
||||||
|
[![Build Status](https://img.shields.io/travis/jmespath/go-jmespath.svg)](https://travis-ci.org/jmespath/go-jmespath)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
See http://jmespath.org for more info.
|
49
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/api.go
generated
vendored
Normal file
49
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/api.go
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package jmespath
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// JmesPath is the epresentation of a compiled JMES path query. A JmesPath is
|
||||||
|
// safe for concurrent use by multiple goroutines.
|
||||||
|
type JMESPath struct {
|
||||||
|
ast ASTNode
|
||||||
|
intr *treeInterpreter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile parses a JMESPath expression and returns, if successful, a JMESPath
|
||||||
|
// object that can be used to match against data.
|
||||||
|
func Compile(expression string) (*JMESPath, error) {
|
||||||
|
parser := NewParser()
|
||||||
|
ast, err := parser.Parse(expression)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
jmespath := &JMESPath{ast: ast, intr: newInterpreter()}
|
||||||
|
return jmespath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustCompile is like Compile but panics if the expression cannot be parsed.
|
||||||
|
// It simplifies safe initialization of global variables holding compiled
|
||||||
|
// JMESPaths.
|
||||||
|
func MustCompile(expression string) *JMESPath {
|
||||||
|
jmespath, err := Compile(expression)
|
||||||
|
if err != nil {
|
||||||
|
panic(`jmespath: Compile(` + strconv.Quote(expression) + `): ` + err.Error())
|
||||||
|
}
|
||||||
|
return jmespath
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search evaluates a JMESPath expression against input data and returns the result.
|
||||||
|
func (jp *JMESPath) Search(data interface{}) (interface{}, error) {
|
||||||
|
return jp.intr.Execute(jp.ast, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search evaluates a JMESPath expression against input data and returns the result.
|
||||||
|
func Search(expression string, data interface{}) (interface{}, error) {
|
||||||
|
intr := newInterpreter()
|
||||||
|
parser := NewParser()
|
||||||
|
ast, err := parser.Parse(expression)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return intr.Execute(ast, data)
|
||||||
|
}
|
16
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go
generated
vendored
Normal file
16
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/astnodetype_string.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// generated by stringer -type astNodeType; DO NOT EDIT
|
||||||
|
|
||||||
|
package jmespath
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
const _astNodeType_name = "ASTEmptyASTComparatorASTCurrentNodeASTExpRefASTFunctionExpressionASTFieldASTFilterProjectionASTFlattenASTIdentityASTIndexASTIndexExpressionASTKeyValPairASTLiteralASTMultiSelectHashASTMultiSelectListASTOrExpressionASTAndExpressionASTNotExpressionASTPipeASTProjectionASTSubexpressionASTSliceASTValueProjection"
|
||||||
|
|
||||||
|
var _astNodeType_index = [...]uint16{0, 8, 21, 35, 44, 65, 73, 92, 102, 113, 121, 139, 152, 162, 180, 198, 213, 229, 245, 252, 265, 281, 289, 307}
|
||||||
|
|
||||||
|
func (i astNodeType) String() string {
|
||||||
|
if i < 0 || i >= astNodeType(len(_astNodeType_index)-1) {
|
||||||
|
return fmt.Sprintf("astNodeType(%d)", i)
|
||||||
|
}
|
||||||
|
return _astNodeType_name[_astNodeType_index[i]:_astNodeType_index[i+1]]
|
||||||
|
}
|
842
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/functions.go
generated
vendored
Normal file
842
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/functions.go
generated
vendored
Normal file
|
@ -0,0 +1,842 @@
|
||||||
|
package jmespath
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type jpFunction func(arguments []interface{}) (interface{}, error)
|
||||||
|
|
||||||
|
type jpType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
jpUnknown jpType = "unknown"
|
||||||
|
jpNumber jpType = "number"
|
||||||
|
jpString jpType = "string"
|
||||||
|
jpArray jpType = "array"
|
||||||
|
jpObject jpType = "object"
|
||||||
|
jpArrayNumber jpType = "array[number]"
|
||||||
|
jpArrayString jpType = "array[string]"
|
||||||
|
jpExpref jpType = "expref"
|
||||||
|
jpAny jpType = "any"
|
||||||
|
)
|
||||||
|
|
||||||
|
type functionEntry struct {
|
||||||
|
name string
|
||||||
|
arguments []argSpec
|
||||||
|
handler jpFunction
|
||||||
|
hasExpRef bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type argSpec struct {
|
||||||
|
types []jpType
|
||||||
|
variadic bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type byExprString struct {
|
||||||
|
intr *treeInterpreter
|
||||||
|
node ASTNode
|
||||||
|
items []interface{}
|
||||||
|
hasError bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *byExprString) Len() int {
|
||||||
|
return len(a.items)
|
||||||
|
}
|
||||||
|
func (a *byExprString) Swap(i, j int) {
|
||||||
|
a.items[i], a.items[j] = a.items[j], a.items[i]
|
||||||
|
}
|
||||||
|
func (a *byExprString) Less(i, j int) bool {
|
||||||
|
first, err := a.intr.Execute(a.node, a.items[i])
|
||||||
|
if err != nil {
|
||||||
|
a.hasError = true
|
||||||
|
// Return a dummy value.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ith, ok := first.(string)
|
||||||
|
if !ok {
|
||||||
|
a.hasError = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
second, err := a.intr.Execute(a.node, a.items[j])
|
||||||
|
if err != nil {
|
||||||
|
a.hasError = true
|
||||||
|
// Return a dummy value.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
jth, ok := second.(string)
|
||||||
|
if !ok {
|
||||||
|
a.hasError = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return ith < jth
|
||||||
|
}
|
||||||
|
|
||||||
|
type byExprFloat struct {
|
||||||
|
intr *treeInterpreter
|
||||||
|
node ASTNode
|
||||||
|
items []interface{}
|
||||||
|
hasError bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *byExprFloat) Len() int {
|
||||||
|
return len(a.items)
|
||||||
|
}
|
||||||
|
func (a *byExprFloat) Swap(i, j int) {
|
||||||
|
a.items[i], a.items[j] = a.items[j], a.items[i]
|
||||||
|
}
|
||||||
|
func (a *byExprFloat) Less(i, j int) bool {
|
||||||
|
first, err := a.intr.Execute(a.node, a.items[i])
|
||||||
|
if err != nil {
|
||||||
|
a.hasError = true
|
||||||
|
// Return a dummy value.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ith, ok := first.(float64)
|
||||||
|
if !ok {
|
||||||
|
a.hasError = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
second, err := a.intr.Execute(a.node, a.items[j])
|
||||||
|
if err != nil {
|
||||||
|
a.hasError = true
|
||||||
|
// Return a dummy value.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
jth, ok := second.(float64)
|
||||||
|
if !ok {
|
||||||
|
a.hasError = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return ith < jth
|
||||||
|
}
|
||||||
|
|
||||||
|
type functionCaller struct {
|
||||||
|
functionTable map[string]functionEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFunctionCaller() *functionCaller {
|
||||||
|
caller := &functionCaller{}
|
||||||
|
caller.functionTable = map[string]functionEntry{
|
||||||
|
"length": {
|
||||||
|
name: "length",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpString, jpArray, jpObject}},
|
||||||
|
},
|
||||||
|
handler: jpfLength,
|
||||||
|
},
|
||||||
|
"starts_with": {
|
||||||
|
name: "starts_with",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpString}},
|
||||||
|
{types: []jpType{jpString}},
|
||||||
|
},
|
||||||
|
handler: jpfStartsWith,
|
||||||
|
},
|
||||||
|
"abs": {
|
||||||
|
name: "abs",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpNumber}},
|
||||||
|
},
|
||||||
|
handler: jpfAbs,
|
||||||
|
},
|
||||||
|
"avg": {
|
||||||
|
name: "avg",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpArrayNumber}},
|
||||||
|
},
|
||||||
|
handler: jpfAvg,
|
||||||
|
},
|
||||||
|
"ceil": {
|
||||||
|
name: "ceil",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpNumber}},
|
||||||
|
},
|
||||||
|
handler: jpfCeil,
|
||||||
|
},
|
||||||
|
"contains": {
|
||||||
|
name: "contains",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpArray, jpString}},
|
||||||
|
{types: []jpType{jpAny}},
|
||||||
|
},
|
||||||
|
handler: jpfContains,
|
||||||
|
},
|
||||||
|
"ends_with": {
|
||||||
|
name: "ends_with",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpString}},
|
||||||
|
{types: []jpType{jpString}},
|
||||||
|
},
|
||||||
|
handler: jpfEndsWith,
|
||||||
|
},
|
||||||
|
"floor": {
|
||||||
|
name: "floor",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpNumber}},
|
||||||
|
},
|
||||||
|
handler: jpfFloor,
|
||||||
|
},
|
||||||
|
"map": {
|
||||||
|
name: "amp",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpExpref}},
|
||||||
|
{types: []jpType{jpArray}},
|
||||||
|
},
|
||||||
|
handler: jpfMap,
|
||||||
|
hasExpRef: true,
|
||||||
|
},
|
||||||
|
"max": {
|
||||||
|
name: "max",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpArrayNumber, jpArrayString}},
|
||||||
|
},
|
||||||
|
handler: jpfMax,
|
||||||
|
},
|
||||||
|
"merge": {
|
||||||
|
name: "merge",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpObject}, variadic: true},
|
||||||
|
},
|
||||||
|
handler: jpfMerge,
|
||||||
|
},
|
||||||
|
"max_by": {
|
||||||
|
name: "max_by",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpArray}},
|
||||||
|
{types: []jpType{jpExpref}},
|
||||||
|
},
|
||||||
|
handler: jpfMaxBy,
|
||||||
|
hasExpRef: true,
|
||||||
|
},
|
||||||
|
"sum": {
|
||||||
|
name: "sum",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpArrayNumber}},
|
||||||
|
},
|
||||||
|
handler: jpfSum,
|
||||||
|
},
|
||||||
|
"min": {
|
||||||
|
name: "min",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpArrayNumber, jpArrayString}},
|
||||||
|
},
|
||||||
|
handler: jpfMin,
|
||||||
|
},
|
||||||
|
"min_by": {
|
||||||
|
name: "min_by",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpArray}},
|
||||||
|
{types: []jpType{jpExpref}},
|
||||||
|
},
|
||||||
|
handler: jpfMinBy,
|
||||||
|
hasExpRef: true,
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
name: "type",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpAny}},
|
||||||
|
},
|
||||||
|
handler: jpfType,
|
||||||
|
},
|
||||||
|
"keys": {
|
||||||
|
name: "keys",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpObject}},
|
||||||
|
},
|
||||||
|
handler: jpfKeys,
|
||||||
|
},
|
||||||
|
"values": {
|
||||||
|
name: "values",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpObject}},
|
||||||
|
},
|
||||||
|
handler: jpfValues,
|
||||||
|
},
|
||||||
|
"sort": {
|
||||||
|
name: "sort",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpArrayString, jpArrayNumber}},
|
||||||
|
},
|
||||||
|
handler: jpfSort,
|
||||||
|
},
|
||||||
|
"sort_by": {
|
||||||
|
name: "sort_by",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpArray}},
|
||||||
|
{types: []jpType{jpExpref}},
|
||||||
|
},
|
||||||
|
handler: jpfSortBy,
|
||||||
|
hasExpRef: true,
|
||||||
|
},
|
||||||
|
"join": {
|
||||||
|
name: "join",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpString}},
|
||||||
|
{types: []jpType{jpArrayString}},
|
||||||
|
},
|
||||||
|
handler: jpfJoin,
|
||||||
|
},
|
||||||
|
"reverse": {
|
||||||
|
name: "reverse",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpArray, jpString}},
|
||||||
|
},
|
||||||
|
handler: jpfReverse,
|
||||||
|
},
|
||||||
|
"to_array": {
|
||||||
|
name: "to_array",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpAny}},
|
||||||
|
},
|
||||||
|
handler: jpfToArray,
|
||||||
|
},
|
||||||
|
"to_string": {
|
||||||
|
name: "to_string",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpAny}},
|
||||||
|
},
|
||||||
|
handler: jpfToString,
|
||||||
|
},
|
||||||
|
"to_number": {
|
||||||
|
name: "to_number",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpAny}},
|
||||||
|
},
|
||||||
|
handler: jpfToNumber,
|
||||||
|
},
|
||||||
|
"not_null": {
|
||||||
|
name: "not_null",
|
||||||
|
arguments: []argSpec{
|
||||||
|
{types: []jpType{jpAny}, variadic: true},
|
||||||
|
},
|
||||||
|
handler: jpfNotNull,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return caller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *functionEntry) resolveArgs(arguments []interface{}) ([]interface{}, error) {
|
||||||
|
if len(e.arguments) == 0 {
|
||||||
|
return arguments, nil
|
||||||
|
}
|
||||||
|
if !e.arguments[len(e.arguments)-1].variadic {
|
||||||
|
if len(e.arguments) != len(arguments) {
|
||||||
|
return nil, errors.New("incorrect number of args")
|
||||||
|
}
|
||||||
|
for i, spec := range e.arguments {
|
||||||
|
userArg := arguments[i]
|
||||||
|
err := spec.typeCheck(userArg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arguments, nil
|
||||||
|
}
|
||||||
|
if len(arguments) < len(e.arguments) {
|
||||||
|
return nil, errors.New("Invalid arity.")
|
||||||
|
}
|
||||||
|
return arguments, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *argSpec) typeCheck(arg interface{}) error {
|
||||||
|
for _, t := range a.types {
|
||||||
|
switch t {
|
||||||
|
case jpNumber:
|
||||||
|
if _, ok := arg.(float64); ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case jpString:
|
||||||
|
if _, ok := arg.(string); ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case jpArray:
|
||||||
|
if isSliceType(arg) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case jpObject:
|
||||||
|
if _, ok := arg.(map[string]interface{}); ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case jpArrayNumber:
|
||||||
|
if _, ok := toArrayNum(arg); ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case jpArrayString:
|
||||||
|
if _, ok := toArrayStr(arg); ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case jpAny:
|
||||||
|
return nil
|
||||||
|
case jpExpref:
|
||||||
|
if _, ok := arg.(expRef); ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Invalid type for: %v, expected: %#v", arg, a.types)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *functionCaller) CallFunction(name string, arguments []interface{}, intr *treeInterpreter) (interface{}, error) {
|
||||||
|
entry, ok := f.functionTable[name]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("unknown function: " + name)
|
||||||
|
}
|
||||||
|
resolvedArgs, err := entry.resolveArgs(arguments)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if entry.hasExpRef {
|
||||||
|
var extra []interface{}
|
||||||
|
extra = append(extra, intr)
|
||||||
|
resolvedArgs = append(extra, resolvedArgs...)
|
||||||
|
}
|
||||||
|
return entry.handler(resolvedArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func jpfAbs(arguments []interface{}) (interface{}, error) {
|
||||||
|
num := arguments[0].(float64)
|
||||||
|
return math.Abs(num), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func jpfLength(arguments []interface{}) (interface{}, error) {
|
||||||
|
arg := arguments[0]
|
||||||
|
if c, ok := arg.(string); ok {
|
||||||
|
return float64(utf8.RuneCountInString(c)), nil
|
||||||
|
} else if isSliceType(arg) {
|
||||||
|
v := reflect.ValueOf(arg)
|
||||||
|
return float64(v.Len()), nil
|
||||||
|
} else if c, ok := arg.(map[string]interface{}); ok {
|
||||||
|
return float64(len(c)), nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("could not compute length()")
|
||||||
|
}
|
||||||
|
|
||||||
|
func jpfStartsWith(arguments []interface{}) (interface{}, error) {
|
||||||
|
search := arguments[0].(string)
|
||||||
|
prefix := arguments[1].(string)
|
||||||
|
return strings.HasPrefix(search, prefix), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func jpfAvg(arguments []interface{}) (interface{}, error) {
|
||||||
|
// We've already type checked the value so we can safely use
|
||||||
|
// type assertions.
|
||||||
|
args := arguments[0].([]interface{})
|
||||||
|
length := float64(len(args))
|
||||||
|
numerator := 0.0
|
||||||
|
for _, n := range args {
|
||||||
|
numerator += n.(float64)
|
||||||
|
}
|
||||||
|
return numerator / length, nil
|
||||||
|
}
|
||||||
|
func jpfCeil(arguments []interface{}) (interface{}, error) {
|
||||||
|
val := arguments[0].(float64)
|
||||||
|
return math.Ceil(val), nil
|
||||||
|
}
|
||||||
|
func jpfContains(arguments []interface{}) (interface{}, error) {
|
||||||
|
search := arguments[0]
|
||||||
|
el := arguments[1]
|
||||||
|
if searchStr, ok := search.(string); ok {
|
||||||
|
if elStr, ok := el.(string); ok {
|
||||||
|
return strings.Index(searchStr, elStr) != -1, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
// Otherwise this is a generic contains for []interface{}
|
||||||
|
general := search.([]interface{})
|
||||||
|
for _, item := range general {
|
||||||
|
if item == el {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
func jpfEndsWith(arguments []interface{}) (interface{}, error) {
|
||||||
|
search := arguments[0].(string)
|
||||||
|
suffix := arguments[1].(string)
|
||||||
|
return strings.HasSuffix(search, suffix), nil
|
||||||
|
}
|
||||||
|
func jpfFloor(arguments []interface{}) (interface{}, error) {
|
||||||
|
val := arguments[0].(float64)
|
||||||
|
return math.Floor(val), nil
|
||||||
|
}
|
||||||
|
func jpfMap(arguments []interface{}) (interface{}, error) {
|
||||||
|
intr := arguments[0].(*treeInterpreter)
|
||||||
|
exp := arguments[1].(expRef)
|
||||||
|
node := exp.ref
|
||||||
|
arr := arguments[2].([]interface{})
|
||||||
|
mapped := make([]interface{}, 0, len(arr))
|
||||||
|
for _, value := range arr {
|
||||||
|
current, err := intr.Execute(node, value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mapped = append(mapped, current)
|
||||||
|
}
|
||||||
|
return mapped, nil
|
||||||
|
}
|
||||||
|
func jpfMax(arguments []interface{}) (interface{}, error) {
|
||||||
|
if items, ok := toArrayNum(arguments[0]); ok {
|
||||||
|
if len(items) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if len(items) == 1 {
|
||||||
|
return items[0], nil
|
||||||
|
}
|
||||||
|
best := items[0]
|
||||||
|
for _, item := range items[1:] {
|
||||||
|
if item > best {
|
||||||
|
best = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best, nil
|
||||||
|
}
|
||||||
|
// Otherwise we're dealing with a max() of strings.
|
||||||
|
items, _ := toArrayStr(arguments[0])
|
||||||
|
if len(items) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if len(items) == 1 {
|
||||||
|
return items[0], nil
|
||||||
|
}
|
||||||
|
best := items[0]
|
||||||
|
for _, item := range items[1:] {
|
||||||
|
if item > best {
|
||||||
|
best = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best, nil
|
||||||
|
}
|
||||||
|
func jpfMerge(arguments []interface{}) (interface{}, error) {
|
||||||
|
final := make(map[string]interface{})
|
||||||
|
for _, m := range arguments {
|
||||||
|
mapped := m.(map[string]interface{})
|
||||||
|
for key, value := range mapped {
|
||||||
|
final[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return final, nil
|
||||||
|
}
|
||||||
|
func jpfMaxBy(arguments []interface{}) (interface{}, error) {
|
||||||
|
intr := arguments[0].(*treeInterpreter)
|
||||||
|
arr := arguments[1].([]interface{})
|
||||||
|
exp := arguments[2].(expRef)
|
||||||
|
node := exp.ref
|
||||||
|
if len(arr) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
} else if len(arr) == 1 {
|
||||||
|
return arr[0], nil
|
||||||
|
}
|
||||||
|
start, err := intr.Execute(node, arr[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch t := start.(type) {
|
||||||
|
case float64:
|
||||||
|
bestVal := t
|
||||||
|
bestItem := arr[0]
|
||||||
|
for _, item := range arr[1:] {
|
||||||
|
result, err := intr.Execute(node, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
current, ok := result.(float64)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("invalid type, must be number")
|
||||||
|
}
|
||||||
|
if current > bestVal {
|
||||||
|
bestVal = current
|
||||||
|
bestItem = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestItem, nil
|
||||||
|
case string:
|
||||||
|
bestVal := t
|
||||||
|
bestItem := arr[0]
|
||||||
|
for _, item := range arr[1:] {
|
||||||
|
result, err := intr.Execute(node, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
current, ok := result.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("invalid type, must be string")
|
||||||
|
}
|
||||||
|
if current > bestVal {
|
||||||
|
bestVal = current
|
||||||
|
bestItem = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestItem, nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("invalid type, must be number of string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func jpfSum(arguments []interface{}) (interface{}, error) {
|
||||||
|
items, _ := toArrayNum(arguments[0])
|
||||||
|
sum := 0.0
|
||||||
|
for _, item := range items {
|
||||||
|
sum += item
|
||||||
|
}
|
||||||
|
return sum, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func jpfMin(arguments []interface{}) (interface{}, error) {
|
||||||
|
if items, ok := toArrayNum(arguments[0]); ok {
|
||||||
|
if len(items) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if len(items) == 1 {
|
||||||
|
return items[0], nil
|
||||||
|
}
|
||||||
|
best := items[0]
|
||||||
|
for _, item := range items[1:] {
|
||||||
|
if item < best {
|
||||||
|
best = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best, nil
|
||||||
|
}
|
||||||
|
items, _ := toArrayStr(arguments[0])
|
||||||
|
if len(items) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if len(items) == 1 {
|
||||||
|
return items[0], nil
|
||||||
|
}
|
||||||
|
best := items[0]
|
||||||
|
for _, item := range items[1:] {
|
||||||
|
if item < best {
|
||||||
|
best = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func jpfMinBy(arguments []interface{}) (interface{}, error) {
|
||||||
|
intr := arguments[0].(*treeInterpreter)
|
||||||
|
arr := arguments[1].([]interface{})
|
||||||
|
exp := arguments[2].(expRef)
|
||||||
|
node := exp.ref
|
||||||
|
if len(arr) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
} else if len(arr) == 1 {
|
||||||
|
return arr[0], nil
|
||||||
|
}
|
||||||
|
start, err := intr.Execute(node, arr[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if t, ok := start.(float64); ok {
|
||||||
|
bestVal := t
|
||||||
|
bestItem := arr[0]
|
||||||
|
for _, item := range arr[1:] {
|
||||||
|
result, err := intr.Execute(node, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
current, ok := result.(float64)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("invalid type, must be number")
|
||||||
|
}
|
||||||
|
if current < bestVal {
|
||||||
|
bestVal = current
|
||||||
|
bestItem = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestItem, nil
|
||||||
|
} else if t, ok := start.(string); ok {
|
||||||
|
bestVal := t
|
||||||
|
bestItem := arr[0]
|
||||||
|
for _, item := range arr[1:] {
|
||||||
|
result, err := intr.Execute(node, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
current, ok := result.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("invalid type, must be string")
|
||||||
|
}
|
||||||
|
if current < bestVal {
|
||||||
|
bestVal = current
|
||||||
|
bestItem = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestItem, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("invalid type, must be number of string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func jpfType(arguments []interface{}) (interface{}, error) {
|
||||||
|
arg := arguments[0]
|
||||||
|
if _, ok := arg.(float64); ok {
|
||||||
|
return "number", nil
|
||||||
|
}
|
||||||
|
if _, ok := arg.(string); ok {
|
||||||
|
return "string", nil
|
||||||
|
}
|
||||||
|
if _, ok := arg.([]interface{}); ok {
|
||||||
|
return "array", nil
|
||||||
|
}
|
||||||
|
if _, ok := arg.(map[string]interface{}); ok {
|
||||||
|
return "object", nil
|
||||||
|
}
|
||||||
|
if arg == nil {
|
||||||
|
return "null", nil
|
||||||
|
}
|
||||||
|
if arg == true || arg == false {
|
||||||
|
return "boolean", nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("unknown type")
|
||||||
|
}
|
||||||
|
func jpfKeys(arguments []interface{}) (interface{}, error) {
|
||||||
|
arg := arguments[0].(map[string]interface{})
|
||||||
|
collected := make([]interface{}, 0, len(arg))
|
||||||
|
for key := range arg {
|
||||||
|
collected = append(collected, key)
|
||||||
|
}
|
||||||
|
return collected, nil
|
||||||
|
}
|
||||||
|
func jpfValues(arguments []interface{}) (interface{}, error) {
|
||||||
|
arg := arguments[0].(map[string]interface{})
|
||||||
|
collected := make([]interface{}, 0, len(arg))
|
||||||
|
for _, value := range arg {
|
||||||
|
collected = append(collected, value)
|
||||||
|
}
|
||||||
|
return collected, nil
|
||||||
|
}
|
||||||
|
func jpfSort(arguments []interface{}) (interface{}, error) {
|
||||||
|
if items, ok := toArrayNum(arguments[0]); ok {
|
||||||
|
d := sort.Float64Slice(items)
|
||||||
|
sort.Stable(d)
|
||||||
|
final := make([]interface{}, len(d))
|
||||||
|
for i, val := range d {
|
||||||
|
final[i] = val
|
||||||
|
}
|
||||||
|
return final, nil
|
||||||
|
}
|
||||||
|
// Otherwise we're dealing with sort()'ing strings.
|
||||||
|
items, _ := toArrayStr(arguments[0])
|
||||||
|
d := sort.StringSlice(items)
|
||||||
|
sort.Stable(d)
|
||||||
|
final := make([]interface{}, len(d))
|
||||||
|
for i, val := range d {
|
||||||
|
final[i] = val
|
||||||
|
}
|
||||||
|
return final, nil
|
||||||
|
}
|
||||||
|
func jpfSortBy(arguments []interface{}) (interface{}, error) {
|
||||||
|
intr := arguments[0].(*treeInterpreter)
|
||||||
|
arr := arguments[1].([]interface{})
|
||||||
|
exp := arguments[2].(expRef)
|
||||||
|
node := exp.ref
|
||||||
|
if len(arr) == 0 {
|
||||||
|
return arr, nil
|
||||||
|
} else if len(arr) == 1 {
|
||||||
|
return arr, nil
|
||||||
|
}
|
||||||
|
start, err := intr.Execute(node, arr[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, ok := start.(float64); ok {
|
||||||
|
sortable := &byExprFloat{intr, node, arr, false}
|
||||||
|
sort.Stable(sortable)
|
||||||
|
if sortable.hasError {
|
||||||
|
return nil, errors.New("error in sort_by comparison")
|
||||||
|
}
|
||||||
|
return arr, nil
|
||||||
|
} else if _, ok := start.(string); ok {
|
||||||
|
sortable := &byExprString{intr, node, arr, false}
|
||||||
|
sort.Stable(sortable)
|
||||||
|
if sortable.hasError {
|
||||||
|
return nil, errors.New("error in sort_by comparison")
|
||||||
|
}
|
||||||
|
return arr, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("invalid type, must be number of string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func jpfJoin(arguments []interface{}) (interface{}, error) {
|
||||||
|
sep := arguments[0].(string)
|
||||||
|
// We can't just do arguments[1].([]string), we have to
|
||||||
|
// manually convert each item to a string.
|
||||||
|
arrayStr := []string{}
|
||||||
|
for _, item := range arguments[1].([]interface{}) {
|
||||||
|
arrayStr = append(arrayStr, item.(string))
|
||||||
|
}
|
||||||
|
return strings.Join(arrayStr, sep), nil
|
||||||
|
}
|
||||||
|
func jpfReverse(arguments []interface{}) (interface{}, error) {
|
||||||
|
if s, ok := arguments[0].(string); ok {
|
||||||
|
r := []rune(s)
|
||||||
|
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
|
||||||
|
r[i], r[j] = r[j], r[i]
|
||||||
|
}
|
||||||
|
return string(r), nil
|
||||||
|
}
|
||||||
|
items := arguments[0].([]interface{})
|
||||||
|
length := len(items)
|
||||||
|
reversed := make([]interface{}, length)
|
||||||
|
for i, item := range items {
|
||||||
|
reversed[length-(i+1)] = item
|
||||||
|
}
|
||||||
|
return reversed, nil
|
||||||
|
}
|
||||||
|
func jpfToArray(arguments []interface{}) (interface{}, error) {
|
||||||
|
if _, ok := arguments[0].([]interface{}); ok {
|
||||||
|
return arguments[0], nil
|
||||||
|
}
|
||||||
|
return arguments[:1:1], nil
|
||||||
|
}
|
||||||
|
func jpfToString(arguments []interface{}) (interface{}, error) {
|
||||||
|
if v, ok := arguments[0].(string); ok {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
result, err := json.Marshal(arguments[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return string(result), nil
|
||||||
|
}
|
||||||
|
func jpfToNumber(arguments []interface{}) (interface{}, error) {
|
||||||
|
arg := arguments[0]
|
||||||
|
if v, ok := arg.(float64); ok {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
if v, ok := arg.(string); ok {
|
||||||
|
conv, err := strconv.ParseFloat(v, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return conv, nil
|
||||||
|
}
|
||||||
|
if _, ok := arg.([]interface{}); ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if _, ok := arg.(map[string]interface{}); ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if arg == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if arg == true || arg == false {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("unknown type")
|
||||||
|
}
|
||||||
|
func jpfNotNull(arguments []interface{}) (interface{}, error) {
|
||||||
|
for _, arg := range arguments {
|
||||||
|
if arg != nil {
|
||||||
|
return arg, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
418
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/interpreter.go
generated
vendored
Normal file
418
vendor/github.com/hashicorp/go-discover/provider/aws/vendor/github.com/jmespath/go-jmespath/interpreter.go
generated
vendored
Normal file
|
@ -0,0 +1,418 @@
|
||||||
|
package jmespath
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* This is a tree based interpreter. It walks the AST and directly
|
||||||
|
interprets the AST to search through a JSON document.
|
||||||
|
*/
|
||||||
|
|
||||||
|
type treeInterpreter struct {
|
||||||
|
fCall *functionCaller
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInterpreter() *treeInterpreter {
|
||||||
|
interpreter := treeInterpreter{}
|
||||||
|
interpreter.fCall = newFunctionCaller()
|
||||||
|
return &interpreter
|
||||||
|
}
|
||||||
|
|
||||||
|
type expRef struct {
|
||||||
|
ref ASTNode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute takes an ASTNode and input data and interprets the AST directly.
|
||||||
|
// It will produce the result of applying the JMESPath expression associated
|
||||||
|
// with the ASTNode to the input data "value".
|
||||||
|
func (intr *treeInterpreter) Execute(node ASTNode, value interface{}) (interface{}, error) {
|
||||||
|
switch node.nodeType {
|
||||||
|
case ASTComparator:
|
||||||
|
left, err := intr.Execute(node.children[0], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
right, err := intr.Execute(node.children[1], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch node.value {
|
||||||
|
case tEQ:
|
||||||
|
return objsEqual(left, right), nil
|
||||||
|
case tNE:
|
||||||
|
return !objsEqual(left, right), nil
|
||||||
|
}
|
||||||
|
leftNum, ok := left.(float64)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
rightNum, ok := right.(float64)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
switch node.value {
|
||||||
|
case tGT:
|
||||||
|
return leftNum > rightNum, nil
|
||||||
|
case tGTE:
|
||||||
|
return leftNum >= rightNum, nil
|
||||||
|
case tLT:
|
||||||
|
return leftNum < rightNum, nil
|
||||||
|
case tLTE:
|
||||||
|
return leftNum <= rightNum, nil
|
||||||
|
}
|
||||||
|
case ASTExpRef:
|
||||||
|
return expRef{ref: node.children[0]}, nil
|
||||||
|
case ASTFunctionExpression:
|
||||||
|
resolvedArgs := []interface{}{}
|
||||||
|
for _, arg := range node.children {
|
||||||
|
current, err := intr.Execute(arg, value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resolvedArgs = append(resolvedArgs, current)
|
||||||
|
}
|
||||||
|
return intr.fCall.CallFunction(node.value.(string), resolvedArgs, intr)
|
||||||
|
case ASTField:
|
||||||
|
if m, ok := value.(map[string]interface{}); ok {
|
||||||
|
key := node.value.(string)
|
||||||
|
return m[key], nil
|
||||||
|
}
|
||||||
|
return intr.fieldFromStruct(node.value.(string), value)
|
||||||
|
case ASTFilterProjection:
|
||||||
|
left, err := intr.Execute(node.children[0], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
sliceType, ok := left.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
if isSliceType(left) {
|
||||||
|
return intr.filterProjectionWithReflection(node, left)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
compareNode := node.children[2]
|
||||||
|
collected := []interface{}{}
|
||||||
|
for _, element := range sliceType {
|
||||||
|
result, err := intr.Execute(compareNode, element)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !isFalse(result) {
|
||||||
|
current, err := intr.Execute(node.children[1], element)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if current != nil {
|
||||||
|
collected = append(collected, current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collected, nil
|
||||||
|
case ASTFlatten:
|
||||||
|
left, err := intr.Execute(node.children[0], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
sliceType, ok := left.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
// If we can't type convert to []interface{}, there's
|
||||||
|
// a chance this could still work via reflection if we're
|
||||||
|
// dealing with user provided types.
|
||||||
|
if isSliceType(left) {
|
||||||
|
return intr.flattenWithReflection(left)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
flattened := []interface{}{}
|
||||||
|
for _, element := range sliceType {
|
||||||
|
if elementSlice, ok := element.([]interface{}); ok {
|
||||||
|
flattened = append(flattened, elementSlice...)
|
||||||
|
} else if isSliceType(element) {
|
||||||
|
reflectFlat := []interface{}{}
|
||||||
|
v := reflect.ValueOf(element)
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
reflectFlat = append(reflectFlat, v.Index(i).Interface())
|
||||||
|
}
|
||||||
|
flattened = append(flattened, reflectFlat...)
|
||||||
|
} else {
|
||||||
|
flattened = append(flattened, element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flattened, nil
|
||||||
|
case ASTIdentity, ASTCurrentNode:
|
||||||
|
return value, nil
|
||||||
|
case ASTIndex:
|
||||||
|
if sliceType, ok := value.([]interface{}); ok {
|
||||||
|
index := node.value.(int)
|
||||||
|
if index < 0 {
|
||||||
|
index += len(sliceType)
|
||||||
|
}
|
||||||
|
if index < len(sliceType) && index >= 0 {
|
||||||
|
return sliceType[index], nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
// Otherwise try via reflection.
|
||||||
|
rv := reflect.ValueOf(value)
|
||||||
|
if rv.Kind() == reflect.Slice {
|
||||||
|
index := node.value.(int)
|
||||||
|
if index < 0 {
|
||||||
|
index += rv.Len()
|
||||||
|
}
|
||||||
|
if index < rv.Len() && index >= 0 {
|
||||||
|
v := rv.Index(index)
|
||||||
|
return v.Interface(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
case ASTKeyValPair:
|
||||||
|
return intr.Execute(node.children[0], value)
|
||||||
|
case ASTLiteral:
|
||||||
|
return node.value, nil
|
||||||
|
case ASTMultiSelectHash:
|
||||||
|
if value == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
collected := make(map[string]interface{})
|
||||||
|
for _, child := range node.children {
|
||||||
|
current, err := intr.Execute(child, value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
key := child.value.(string)
|
||||||
|
collected[key] = current
|
||||||
|
}
|
||||||
|
return collected, nil
|
||||||
|
case ASTMultiSelectList:
|
||||||
|
if value == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
collected := []interface{}{}
|
||||||
|
for _, child := range node.children {
|
||||||
|
current, err := intr.Execute(child, value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
collected = append(collected, current)
|
||||||
|
}
|
||||||
|
return collected, nil
|
||||||
|
case ASTOrExpression:
|
||||||
|
matched, err := intr.Execute(node.children[0], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if isFalse(matched) {
|
||||||
|
matched, err = intr.Execute(node.children[1], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matched, nil
|
||||||
|
case ASTAndExpression:
|
||||||
|
matched, err := intr.Execute(node.children[0], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if isFalse(matched) {
|
||||||
|
return matched, nil
|
||||||
|
}
|
||||||
|
return intr.Execute(node.children[1], value)
|
||||||
|
case ASTNotExpression:
|
||||||
|
matched, err := intr.Execute(node.children[0], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if isFalse(matched) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
case ASTPipe:
|
||||||
|
result := value
|
||||||
|
var err error
|
||||||
|
for _, child := range node.children {
|
||||||
|
result, err = intr.Execute(child, result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
case ASTProjection:
|
||||||
|
left, err := intr.Execute(node.children[0], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sliceType, ok := left.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
if isSliceType(left) {
|
||||||
|
return intr.projectWithReflection(node, left)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
collected := []interface{}{}
|
||||||
|
var current interface{}
|
||||||
|
for _, element := range sliceType {
|
||||||
|
current, err = intr.Execute(node.children[1], element)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if current != nil {
|
||||||
|
collected = append(collected, current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collected, nil
|
||||||
|
case ASTSubexpression, ASTIndexExpression:
|
||||||
|
left, err := intr.Execute(node.children[0], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return intr.Execute(node.children[1], left)
|
||||||
|
case ASTSlice:
|
||||||
|
sliceType, ok := value.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
if isSliceType(value) {
|
||||||
|
return intr.sliceWithReflection(node, value)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
parts := node.value.([]*int)
|
||||||
|
sliceParams := make([]sliceParam, 3)
|
||||||
|
for i, part := range parts {
|
||||||
|
if part != nil {
|
||||||
|
sliceParams[i].Specified = true
|
||||||
|
sliceParams[i].N = *part
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slice(sliceType, sliceParams)
|
||||||
|
case ASTValueProjection:
|
||||||
|
left, err := intr.Execute(node.children[0], value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
mapType, ok := left.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
values := make([]interface{}, len(mapType))
|
||||||
|
for _, value := range mapType {
|
||||||
|
values = append(values, value)
|
||||||
|
}
|
||||||
|
collected := []interface{}{}
|
||||||
|
for _, element := range values {
|
||||||
|
current, err := intr.Execute(node.children[1], element)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if current != nil {
|
||||||
|
collected = append(collected, current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collected, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("Unknown AST node: " + node.nodeType.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (intr *treeInterpreter) fieldFromStruct(key string, value interface{}) (interface{}, error) {
|
||||||
|
rv := reflect.ValueOf(value)
|
||||||
|
first, n := utf8.DecodeRuneInString(key)
|
||||||
|
fieldName := string(unicode.ToUpper(first)) + key[n:]
|
||||||
|
if rv.Kind() == reflect.Struct {
|
||||||
|
v := rv.FieldByName(fieldName)
|
||||||
|
if !v.IsValid() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return v.Interface(), nil
|
||||||
|
} else if rv.Kind() == reflect.Ptr {
|
||||||
|
// Handle multiple levels of indirection?
|
||||||
|
if rv.IsNil() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
rv = rv.Elem()
|
||||||
|
v := rv.FieldByName(fieldName)
|
||||||
|
if !v.IsValid() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return v.Interface(), nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (intr *treeInterpreter) flattenWithReflection(value interface{}) (interface{}, error) {
|
||||||
|
v := reflect.ValueOf(value)
|
||||||
|
flattened := []interface{}{}
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
element := v.Index(i).Interface()
|
||||||
|
if reflect.TypeOf(element).Kind() == reflect.Slice {
|
||||||
|
// Then insert the contents of the element
|
||||||
|
// slice into the flattened slice,
|
||||||
|
// i.e flattened = append(flattened, mySlice...)
|
||||||
|
elementV := reflect.ValueOf(element)
|
||||||
|
for j := 0; j < elementV.Len(); j++ {
|
||||||
|
flattened = append(
|
||||||
|
flattened, elementV.Index(j).Interface())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
flattened = append(flattened, element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flattened, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (intr *treeInterpreter) sliceWithReflection(node ASTNode, value interface{}) (interface{}, error) {
|
||||||
|
v := reflect.ValueOf(value)
|
||||||
|
parts := node.value.([]*int)
|
||||||
|
sliceParams := make([]sliceParam, 3)
|
||||||
|
for i, part := range parts {
|
||||||
|
if part != nil {
|
||||||
|
sliceParams[i].Specified = true
|
||||||
|
sliceParams[i].N = *part
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final := []interface{}{}
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
element := v.Index(i).Interface()
|
||||||
|
final = append(final, element)
|
||||||
|
}
|
||||||
|
return slice(final, sliceParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (intr *treeInterpreter) filterProjectionWithReflection(node ASTNode, value interface{}) (interface{}, error) {
|
||||||
|
compareNode := node.children[2]
|
||||||
|
collected := []interface{}{}
|
||||||
|
v := reflect.ValueOf(value)
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
element := v.Index(i).Interface()
|
||||||
|
result, err := intr.Execute(compareNode, element)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !isFalse(result) {
|
||||||
|
current, err := intr.Execute(node.children[1], element)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if current != nil {
|
||||||
|
collected = append(collected, current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collected, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (intr *treeInterpreter) projectWithReflection(node ASTNode, value interface{}) (interface{}, error) {
|
||||||
|
collected := []interface{}{}
|
||||||
|
v := reflect.ValueOf(value)
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
element := v.Index(i).Interface()
|
||||||
|
result, err := intr.Execute(node.children[1], element)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if result != nil {
|
||||||
|
collected = append(collected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collected, nil
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue