Update deps

This commit is contained in:
Jeff Mitchell 2016-09-02 18:05:09 -04:00
parent 999c133db9
commit 487e05d25c
204 changed files with 11131 additions and 2336 deletions

202
vendor/camlistore.org/COPYING generated vendored
View File

@ -1,202 +0,0 @@
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.

View File

@ -1,262 +0,0 @@
/*
Copyright 2011 Google Inc.
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 netutil identifies the system userid responsible for
// localhost TCP connections.
package netutil // import "camlistore.org/pkg/netutil"
import (
"bufio"
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"os"
"os/exec"
"regexp"
"runtime"
"strconv"
"strings"
)
var (
ErrNotFound = errors.New("netutil: connection not found")
ErrUnsupportedOS = errors.New("netutil: not implemented on this operating system")
)
// ConnUserid returns the uid that owns the given localhost connection.
// The returned error is ErrNotFound if the connection wasn't found.
func ConnUserid(conn net.Conn) (uid int, err error) {
return AddrPairUserid(conn.LocalAddr(), conn.RemoteAddr())
}
// HostPortToIP parses a host:port to a TCPAddr without resolving names.
// If given a context IP, it will resolve localhost to match the context's IP family.
func HostPortToIP(hostport string, ctx *net.TCPAddr) (hostaddr *net.TCPAddr, err error) {
host, port, err := net.SplitHostPort(hostport)
if err != nil {
return nil, err
}
iport, err := strconv.Atoi(port)
if err != nil || iport < 0 || iport > 0xFFFF {
return nil, fmt.Errorf("invalid port %d", iport)
}
var addr net.IP
if ctx != nil && host == "localhost" {
if ctx.IP.To4() != nil {
addr = net.IPv4(127, 0, 0, 1)
} else {
addr = net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
}
} else if addr = net.ParseIP(host); addr == nil {
return nil, fmt.Errorf("could not parse IP %s", host)
}
return &net.TCPAddr{IP: addr, Port: iport}, nil
}
// AddrPairUserid returns the local userid who owns the TCP connection
// given by the local and remote ip:port (lipport and ripport,
// respectively). Returns ErrNotFound for the error if the TCP connection
// isn't found.
func AddrPairUserid(local, remote net.Addr) (uid int, err error) {
lAddr, lOk := local.(*net.TCPAddr)
rAddr, rOk := remote.(*net.TCPAddr)
if !(lOk && rOk) {
return -1, fmt.Errorf("netutil: Could not convert Addr to TCPAddr.")
}
localv4 := (lAddr.IP.To4() != nil)
remotev4 := (rAddr.IP.To4() != nil)
if localv4 != remotev4 {
return -1, fmt.Errorf("netutil: address pairs of different families; localv4=%v, remotev4=%v",
localv4, remotev4)
}
switch runtime.GOOS {
case "darwin":
return uidFromLsof(lAddr.IP, lAddr.Port, rAddr.IP, rAddr.Port)
case "freebsd":
return uidFromSockstat(lAddr.IP, lAddr.Port, rAddr.IP, rAddr.Port)
case "linux":
file := "/proc/net/tcp"
if !localv4 {
file = "/proc/net/tcp6"
}
f, err := os.Open(file)
if err != nil {
return -1, fmt.Errorf("Error opening %s: %v", file, err)
}
defer f.Close()
return uidFromProcReader(lAddr.IP, lAddr.Port, rAddr.IP, rAddr.Port, f)
}
return 0, ErrUnsupportedOS
}
func toLinuxIPv4Order(b []byte) []byte {
binary.BigEndian.PutUint32(b, binary.LittleEndian.Uint32(b))
return b
}
func toLinuxIPv6Order(b []byte) []byte {
for i := 0; i < 16; i += 4 {
sb := b[i : i+4]
binary.BigEndian.PutUint32(sb, binary.LittleEndian.Uint32(sb))
}
return b
}
type maybeBrackets net.IP
func (p maybeBrackets) String() string {
s := net.IP(p).String()
if strings.Contains(s, ":") {
return "[" + s + "]"
}
return s
}
// Changed by tests.
var uidFromUsername = uidFromUsernameFn
func uidFromLsof(lip net.IP, lport int, rip net.IP, rport int) (uid int, err error) {
seek := fmt.Sprintf("%s:%d->%s:%d", maybeBrackets(lip), lport, maybeBrackets(rip), rport)
seekb := []byte(seek)
if _, err = exec.LookPath("lsof"); err != nil {
return
}
cmd := exec.Command("lsof",
"-b", // avoid system calls that could block
"-w", // and don't warn about cases where -b fails
"-n", // don't resolve network names
"-P", // don't resolve network ports,
// TODO(bradfitz): pass down the uid we care about, then do: ?
//"-a", // AND the following together:
// "-u", strconv.Itoa(uid) // just this uid
"-itcp") // we only care about TCP connections
stdout, err := cmd.StdoutPipe()
if err != nil {
return
}
defer cmd.Wait()
defer stdout.Close()
err = cmd.Start()
if err != nil {
return
}
defer cmd.Process.Kill()
br := bufio.NewReader(stdout)
for {
line, err := br.ReadSlice('\n')
if err == io.EOF {
break
}
if err != nil {
return -1, err
}
if !bytes.Contains(line, seekb) {
continue
}
// SystemUIS 276 bradfitz 15u IPv4 0xffffff801a7c74e0 0t0 TCP 127.0.0.1:56718->127.0.0.1:5204 (ESTABLISHED)
f := bytes.Fields(line)
if len(f) < 8 {
continue
}
username := string(f[2])
return uidFromUsername(username)
}
return -1, ErrNotFound
}
func uidFromSockstat(lip net.IP, lport int, rip net.IP, rport int) (int, error) {
cmd := exec.Command("sockstat", "-Ptcp")
stdout, err := cmd.StdoutPipe()
if err != nil {
return -1, err
}
defer cmd.Wait()
defer stdout.Close()
err = cmd.Start()
if err != nil {
return -1, err
}
defer cmd.Process.Kill()
return uidFromSockstatReader(lip, lport, rip, rport, stdout)
}
func uidFromSockstatReader(lip net.IP, lport int, rip net.IP, rport int, r io.Reader) (int, error) {
pat, err := regexp.Compile(fmt.Sprintf(`^([^ ]+).*%s:%d *%s:%d$`,
lip.String(), lport, rip.String(), rport))
if err != nil {
return -1, err
}
scanner := bufio.NewScanner(r)
for scanner.Scan() {
l := scanner.Text()
m := pat.FindStringSubmatch(l)
if len(m) == 2 {
return uidFromUsername(m[1])
}
}
if err := scanner.Err(); err != nil {
return -1, err
}
return -1, ErrNotFound
}
func uidFromProcReader(lip net.IP, lport int, rip net.IP, rport int, r io.Reader) (uid int, err error) {
buf := bufio.NewReader(r)
localHex := ""
remoteHex := ""
ipv4 := lip.To4() != nil
if ipv4 {
// In the kernel, the port is run through ntohs(), and
// the inet_request_socket in
// include/net/inet_socket.h says the "loc_addr" and
// "rmt_addr" fields are __be32, but get_openreq4's
// printf of them is raw, without byte order
// converstion.
localHex = fmt.Sprintf("%08X:%04X", toLinuxIPv4Order([]byte(lip.To4())), lport)
remoteHex = fmt.Sprintf("%08X:%04X", toLinuxIPv4Order([]byte(rip.To4())), rport)
} else {
localHex = fmt.Sprintf("%032X:%04X", toLinuxIPv6Order([]byte(lip.To16())), lport)
remoteHex = fmt.Sprintf("%032X:%04X", toLinuxIPv6Order([]byte(rip.To16())), rport)
}
for {
line, err := buf.ReadString('\n')
if err != nil {
return -1, ErrNotFound
}
parts := strings.Fields(strings.TrimSpace(line))
if len(parts) < 8 {
continue
}
// log.Printf("parts[1] = %q; localHex = %q", parts[1], localHex)
if parts[1] == localHex && parts[2] == remoteHex {
uid, err = strconv.Atoi(parts[7])
return uid, err
}
}
panic("unreachable")
}

View File

@ -1,39 +0,0 @@
// +build !nocgo
/*
Copyright 2016 The Camlistore Authors.
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 netutil identifies the system userid responsible for
// localhost TCP connections.
package netutil // import "camlistore.org/pkg/netutil"
import (
"os"
"os/user"
"strconv"
)
func uidFromUsernameFn(username string) (uid int, err error) {
if uid := os.Getuid(); uid != 0 && username == os.Getenv("USER") {
return uid, nil
}
u, err := user.Lookup(username)
if err == nil {
uid, err := strconv.Atoi(u.Uid)
return uid, err
}
return 0, err
}

View File

@ -1,32 +0,0 @@
// +build nocgo
/*
Copyright 2016 The Camlistore Authors.
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 netutil identifies the system userid responsible for
// localhost TCP connections.
package netutil // import "camlistore.org/pkg/netutil"
import (
"os"
)
func uidFromUsernameFn(username string) (uid int, err error) {
if uid := os.Getuid(); uid != 0 && username == os.Getenv("USER") {
return uid, nil
}
return 0, err
}

View File

@ -1,165 +0,0 @@
/*
Copyright 2014 The Camlistore Authors
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 netutil
import (
"errors"
"fmt"
"net"
"net/url"
"strings"
"time"
)
// AwaitReachable tries to make a TCP connection to addr regularly.
// It returns an error if it's unable to make a connection before maxWait.
func AwaitReachable(addr string, maxWait time.Duration) error {
done := time.Now().Add(maxWait)
for time.Now().Before(done) {
c, err := net.Dial("tcp", addr)
if err == nil {
c.Close()
return nil
}
time.Sleep(100 * time.Millisecond)
}
return fmt.Errorf("%v unreachable for %v", addr, maxWait)
}
// HostPort takes a urlStr string URL, and returns a host:port string suitable
// to passing to net.Dial, with the port set as the scheme's default port if
// absent.
func HostPort(urlStr string) (string, error) {
// TODO: rename this function to URLHostPort instead, like
// ListenHostPort below.
u, err := url.Parse(urlStr)
if err != nil {
return "", fmt.Errorf("could not parse %q as a url: %v", urlStr, err)
}
if u.Scheme == "" {
return "", fmt.Errorf("url %q has no scheme", urlStr)
}
hostPort := u.Host
if hostPort == "" || strings.HasPrefix(hostPort, ":") {
return "", fmt.Errorf("url %q has no host", urlStr)
}
idx := strings.Index(hostPort, "]")
if idx == -1 {
idx = 0
}
if !strings.Contains(hostPort[idx:], ":") {
if u.Scheme == "https" {
hostPort += ":443"
} else {
hostPort += ":80"
}
}
return hostPort, nil
}
// ListenHostPort maps a listen address into a host:port string.
// If the host part in listenAddr is empty or 0.0.0.0, localhost
// is used instead.
func ListenHostPort(listenAddr string) (string, error) {
hp := listenAddr
if strings.HasPrefix(hp, ":") {
hp = "localhost" + hp
} else if strings.HasPrefix(hp, "0.0.0.0:") {
hp = "localhost:" + hp[len("0.0.0.0:"):]
}
if _, _, err := net.SplitHostPort(hp); err != nil {
return "", err
}
return hp, nil
}
// ListenOnLocalRandomPort returns a TCP listener on a random
// localhost port.
func ListenOnLocalRandomPort() (net.Listener, error) {
ip, err := Localhost()
if err != nil {
return nil, err
}
return net.ListenTCP("tcp", &net.TCPAddr{IP: ip, Port: 0})
}
// Localhost returns the first address found when
// doing a lookup of "localhost". If not successful,
// it looks for an ip on the loopback interfaces.
func Localhost() (net.IP, error) {
if ip := localhostLookup(); ip != nil {
return ip, nil
}
if ip := loopbackIP(); ip != nil {
return ip, nil
}
return nil, errors.New("No loopback ip found.")
}
// localhostLookup looks for a loopback IP by resolving localhost.
func localhostLookup() net.IP {
if ips, err := net.LookupIP("localhost"); err == nil && len(ips) > 0 {
return ips[0]
}
return nil
}
// loopbackIP returns the first loopback IP address sniffing network
// interfaces or nil if none is found.
func loopbackIP() net.IP {
interfaces, err := net.Interfaces()
if err != nil {
return nil
}
for _, inf := range interfaces {
const flagUpLoopback = net.FlagUp | net.FlagLoopback
if inf.Flags&flagUpLoopback == flagUpLoopback {
addrs, _ := inf.Addrs()
for _, addr := range addrs {
ip, _, err := net.ParseCIDR(addr.String())
if err == nil && ip.IsLoopback() {
return ip
}
}
}
}
return nil
}
// RandPort returns a random port to listen on.
func RandPort() (int, error) {
var port int
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return port, err
}
listener, err := net.ListenTCP("tcp", addr)
if err != nil {
return port, fmt.Errorf("could not listen to find random port: %v", err)
}
randAddr := listener.Addr().(*net.TCPAddr)
if err := listener.Close(); err != nil {
return port, fmt.Errorf("could not close random listener: %v", err)
}
return randAddr.Port, nil
}
// HasPort, given a string of the form "host", "host:port", or
// "[ipv6::address]:port", returns true if the string includes a port.
func HasPort(s string) bool {
return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
}

View File

@ -0,0 +1,5 @@
# Azure Storage SDK for Go
The `github.com/Azure/azure-sdk-for-go/storage` package is used to perform operations in Azure Storage Service. To manage your storage accounts (Azure Resource Manager / ARM), use the [github.com/Azure/azure-sdk-for-go/arm/storage](../arm/storage) package. For your classic storage accounts (Azure Service Management / ASM), use [github.com/Azure/azure-sdk-for-go/management/storageservice](../management/storageservice) package.
This package includes support for [Azure Storage Emulator](https://azure.microsoft.com/documentation/articles/storage-use-emulator/)

View File

@ -111,6 +111,8 @@ type BlobProperties struct {
ContentLength int64 `xml:"Content-Length"`
ContentType string `xml:"Content-Type"`
ContentEncoding string `xml:"Content-Encoding"`
CacheControl string `xml:"Cache-Control"`
ContentLanguage string `xml:"Cache-Language"`
BlobType BlobType `xml:"x-ms-blob-blob-type"`
SequenceNumber int64 `xml:"x-ms-blob-sequence-number"`
CopyID string `xml:"CopyId"`
@ -122,6 +124,16 @@ type BlobProperties struct {
LeaseStatus string `xml:"LeaseStatus"`
}
// BlobHeaders contains various properties of a blob and is an entry
// in SetBlobProperties
type BlobHeaders struct {
ContentMD5 string `header:"x-ms-blob-content-md5"`
ContentLanguage string `header:"x-ms-blob-content-language"`
ContentEncoding string `header:"x-ms-blob-content-encoding"`
ContentType string `header:"x-ms-blob-content-type"`
CacheControl string `header:"x-ms-blob-cache-control"`
}
// BlobListResponse contains the response fields from ListBlobs call.
//
// See https://msdn.microsoft.com/en-us/library/azure/dd135734.aspx
@ -474,7 +486,6 @@ func (b BlobStorageClient) ListBlobs(container string, params ListBlobsParameter
func (b BlobStorageClient) BlobExists(container, name string) (bool, error) {
verb := "HEAD"
uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), url.Values{})
headers := b.client.getStandardHeaders()
resp, err := b.client.exec(verb, uri, headers, nil)
if resp != nil {
@ -590,6 +601,9 @@ func (b BlobStorageClient) GetBlobProperties(container, name string) (*BlobPrope
ContentMD5: resp.headers.Get("Content-MD5"),
ContentLength: contentLength,
ContentEncoding: resp.headers.Get("Content-Encoding"),
ContentType: resp.headers.Get("Content-Type"),
CacheControl: resp.headers.Get("Cache-Control"),
ContentLanguage: resp.headers.Get("Content-Language"),
SequenceNumber: sequenceNum,
CopyCompletionTime: resp.headers.Get("x-ms-copy-completion-time"),
CopyStatusDescription: resp.headers.Get("x-ms-copy-status-description"),
@ -602,6 +616,34 @@ func (b BlobStorageClient) GetBlobProperties(container, name string) (*BlobPrope
}, nil
}
// SetBlobProperties replaces the BlobHeaders for the specified blob.
//
// Some keys may be converted to Camel-Case before sending. All keys
// are returned in lower case by GetBlobProperties. HTTP header names
// are case-insensitive so case munging should not matter to other
// applications either.
//
// See https://msdn.microsoft.com/en-us/library/azure/ee691966.aspx
func (b BlobStorageClient) SetBlobProperties(container, name string, blobHeaders BlobHeaders) error {
params := url.Values{"comp": {"properties"}}
uri := b.client.getEndpoint(blobServiceName, pathForBlob(container, name), params)
headers := b.client.getStandardHeaders()
extraHeaders := headersFromStruct(blobHeaders)
for k, v := range extraHeaders {
headers[k] = v
}
resp, err := b.client.exec("PUT", uri, headers, nil)
if err != nil {
return err
}
defer resp.body.Close()
return checkRespCode(resp.statusCode, []int{http.StatusOK})
}
// SetBlobMetadata replaces the metadata for the specified blob.
//
// Some keys may be converted to Camel-Case before sending. All keys
@ -1033,9 +1075,24 @@ func (b BlobStorageClient) GetBlobSASURI(container, name string, expiry time.Tim
blobURL = b.GetBlobURL(container, name)
)
canonicalizedResource, err := b.client.buildCanonicalizedResource(blobURL)
if err != nil {
return "", err
}
// "The canonicalizedresouce portion of the string is a canonical path to the signed resource.
// It must include the service name (blob, table, queue or file) for version 2015-02-21 or
// later, the storage account name, and the resource name, and must be URL-decoded.
// -- https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
// We need to replace + with %2b first to avoid being treated as a space (which is correct for query strings, but not the path component).
canonicalizedResource = strings.Replace(canonicalizedResource, "+", "%2b", -1)
canonicalizedResource, err = url.QueryUnescape(canonicalizedResource)
if err != nil {
return "", err
}
signedExpiry := expiry.UTC().Format(time.RFC3339)
signedResource := "b"

View File

@ -29,10 +29,20 @@ const (
defaultUseHTTPS = true
// StorageEmulatorAccountName is the fixed storage account used by Azure Storage Emulator
StorageEmulatorAccountName = "devstoreaccount1"
// StorageEmulatorAccountKey is the the fixed storage account used by Azure Storage Emulator
StorageEmulatorAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
blobServiceName = "blob"
tableServiceName = "table"
queueServiceName = "queue"
fileServiceName = "file"
storageEmulatorBlob = "127.0.0.1:10000"
storageEmulatorTable = "127.0.0.1:10002"
storageEmulatorQueue = "127.0.0.1:10001"
)
// Client is the object that needs to be constructed to perform
@ -114,9 +124,18 @@ func (e UnexpectedStatusCodeError) Got() int {
// NewBasicClient constructs a Client with given storage service name and
// key.
func NewBasicClient(accountName, accountKey string) (Client, error) {
if accountName == StorageEmulatorAccountName {
return NewEmulatorClient()
}
return NewClient(accountName, accountKey, DefaultBaseURL, DefaultAPIVersion, defaultUseHTTPS)
}
//NewEmulatorClient contructs a Client intended to only work with Azure
//Storage Emulator
func NewEmulatorClient() (Client, error) {
return NewClient(StorageEmulatorAccountName, StorageEmulatorAccountKey, DefaultBaseURL, DefaultAPIVersion, false)
}
// NewClient constructs a Client. This should be used if the caller wants
// to specify whether to use HTTPS, a specific REST API version or a custom
// storage endpoint than Azure Public Cloud.
@ -149,8 +168,19 @@ func (c Client) getBaseURL(service string) string {
if c.useHTTPS {
scheme = "https"
}
host := fmt.Sprintf("%s.%s.%s", c.accountName, service, c.baseURL)
host := ""
if c.accountName == StorageEmulatorAccountName {
switch service {
case blobServiceName:
host = storageEmulatorBlob
case tableServiceName:
host = storageEmulatorTable
case queueServiceName:
host = storageEmulatorQueue
}
} else {
host = fmt.Sprintf("%s.%s.%s", c.accountName, service, c.baseURL)
}
u := &url.URL{
Scheme: scheme,
@ -165,8 +195,13 @@ func (c Client) getEndpoint(service, path string, params url.Values) string {
panic(err)
}
if path == "" {
path = "/" // API doesn't accept path segments not starting with '/'
// API doesn't accept path segments not starting with '/'
if !strings.HasPrefix(path, "/") {
path = fmt.Sprintf("/%v", path)
}
if c.accountName == StorageEmulatorAccountName {
path = fmt.Sprintf("/%v%v", StorageEmulatorAccountName, path)
}
u.Path = path
@ -200,7 +235,7 @@ func (c Client) GetFileService() FileServiceClient {
func (c Client) createAuthorizationHeader(canonicalizedString string) string {
signature := c.computeHmac256(canonicalizedString)
return fmt.Sprintf("%s %s:%s", "SharedKey", c.accountName, signature)
return fmt.Sprintf("%s %s:%s", "SharedKey", c.getCanonicalizedAccountName(), signature)
}
func (c Client) getAuthorizationHeader(verb, url string, headers map[string]string) (string, error) {
@ -220,6 +255,12 @@ func (c Client) getStandardHeaders() map[string]string {
}
}
func (c Client) getCanonicalizedAccountName() string {
// since we may be trying to access a secondary storage account, we need to
// remove the -secondary part of the storage name
return strings.TrimSuffix(c.accountName, "-secondary")
}
func (c Client) buildCanonicalizedHeader(headers map[string]string) string {
cm := make(map[string]string)
@ -261,7 +302,7 @@ func (c Client) buildCanonicalizedResourceTable(uri string) (string, error) {
return "", fmt.Errorf(errMsg, err.Error())
}
cr := "/" + c.accountName
cr := "/" + c.getCanonicalizedAccountName()
if len(u.Path) > 0 {
cr += u.Path
@ -277,10 +318,13 @@ func (c Client) buildCanonicalizedResource(uri string) (string, error) {
return "", fmt.Errorf(errMsg, err.Error())
}
cr := "/" + c.accountName
cr := "/" + c.getCanonicalizedAccountName()
if len(u.Path) > 0 {
cr += u.Path
// Any portion of the CanonicalizedResource string that is derived from
// the resource's URI should be encoded exactly as it is in the URI.
// -- https://msdn.microsoft.com/en-gb/library/azure/dd179428.aspx
cr += u.EscapedPath()
}
params, err := url.ParseQuery(u.RawQuery)
@ -343,7 +387,6 @@ func (c Client) exec(verb, url string, headers map[string]string, body io.Reader
return nil, err
}
headers["Authorization"] = authHeader
if err != nil {
return nil, err
}

View File

@ -47,6 +47,9 @@ func (f FileServiceClient) CreateShareIfNotExists(name string) (bool, error) {
// CreateShare creates a Azure File Share and returns its response
func (f FileServiceClient) createShare(name string) (*storageResponse, error) {
if err := f.checkForStorageEmulator(); err != nil {
return nil, err
}
uri := f.client.getEndpoint(fileServiceName, pathForFileShare(name), url.Values{"restype": {"share"}})
headers := f.client.getStandardHeaders()
return f.client.exec("PUT", uri, headers, nil)
@ -86,6 +89,18 @@ func (f FileServiceClient) DeleteShareIfExists(name string) (bool, error) {
// deleteShare makes the call to Delete Share operation endpoint and returns
// the response
func (f FileServiceClient) deleteShare(name string) (*storageResponse, error) {
if err := f.checkForStorageEmulator(); err != nil {
return nil, err
}
uri := f.client.getEndpoint(fileServiceName, pathForFileShare(name), url.Values{"restype": {"share"}})
return f.client.exec("DELETE", uri, f.client.getStandardHeaders(), nil)
}
//checkForStorageEmulator determines if the client is setup for use with
//Azure Storage Emulator, and returns a relevant error
func (f FileServiceClient) checkForStorageEmulator() error {
if f.client.accountName == StorageEmulatorAccountName {
return fmt.Errorf("Error: File service is not currently supported by Azure Storage Emulator")
}
return nil
}

View File

@ -98,6 +98,10 @@ func (c *TableServiceClient) QueryTableEntities(tableName AzureTable, previousCo
resp, err := c.client.execTable("GET", uri, headers, nil)
if err != nil {
return nil, nil, err
}
contToken := extractContinuationTokenFromHeaders(resp.headers)
if err != nil {

View File

@ -11,6 +11,7 @@ import (
"io/ioutil"
"net/http"
"net/url"
"reflect"
"time"
)
@ -69,3 +70,16 @@ func xmlMarshal(v interface{}) (io.Reader, int, error) {
}
return bytes.NewReader(b), len(b), nil
}
func headersFromStruct(v interface{}) map[string]string {
headers := make(map[string]string)
value := reflect.ValueOf(v)
for i := 0; i < value.NumField(); i++ {
key := value.Type().Field(i).Tag.Get("header")
val := value.Field(i).String()
if val != "" {
headers[key] = val
}
}
return headers
}

View File

@ -44,7 +44,7 @@ type Error interface {
// 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 occured in the batch.
// that occurred in the batch.
//
// Deprecated: Replaced with BatchedErrors. Only defined for backwards
// compatibility.
@ -64,7 +64,7 @@ type BatchError interface {
// 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 occured in the batch.
// that occurred in the batch.
//
// Replaces BatchError
type BatchedErrors interface {

View File

@ -98,7 +98,7 @@ func (b baseError) OrigErr() error {
return NewBatchError(err.Code(), err.Message(), b.errs[1:])
}
return NewBatchError("BatchedErrors",
"multiple errors occured", b.errs)
"multiple errors occurred", b.errs)
}
}

View File

@ -3,6 +3,7 @@ package awsutil
import (
"io"
"reflect"
"time"
)
// Copy deeply copies a src structure to dst. Useful for copying request and
@ -49,7 +50,14 @@ func rcopy(dst, src reflect.Value, root bool) {
} else {
e := src.Type().Elem()
if dst.CanSet() && !src.IsNil() {
dst.Set(reflect.New(e))
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

View File

@ -87,9 +87,18 @@ const logReqMsg = `DEBUG: Request %s/%s Details:
%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, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)
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
@ -107,11 +116,21 @@ const logRespMsg = `DEBUG: Response %s/%s Details:
%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, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
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()

View File

@ -7,24 +7,36 @@ import (
"github.com/aws/aws-sdk-go/aws/credentials"
)
// 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.
// 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.
// RequestRetryer is an alias for a type that implements the request.Retryer
// interface.
type RequestRetryer interface{}
// A Config provides service configuration for service clients. By default,
// all clients will use the {defaults.DefaultConfig} structure.
// 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 retreive
// credentials.
// 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
// 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
@ -63,11 +75,12 @@ type Config struct {
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.
// 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.
// 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.
@ -82,8 +95,8 @@ type Config struct {
//
Retryer RequestRetryer
// Disables semantic parameter validation, which validates input for missing
// required fields and/or other semantic request input errors.
// 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.,
@ -91,8 +104,8 @@ type Config struct {
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
// 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.
@ -109,36 +122,63 @@ type Config struct {
// 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
// `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 experiance issues
// with proxies or thrid party S3 compatible services.
// 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.
// 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.
// 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.
//
// Not compatible with UseDualStack requests will fail if both flags are
// specified.
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.
// 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.New() in order to disable the EC2Metadata
// overriding the timeout for default credentials chain.
// Must be set and provided to the session.NewSession() in order to disable
// the EC2Metadata overriding the timeout for default credentials chain.
//
// Example:
// sess := session.New(aws.NewConfig().WithEC2MetadataDiableTimeoutOverride(true))
// 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
@ -147,11 +187,19 @@ type Config struct {
SleepDelay func(time.Duration)
}
// NewConfig returns a new Config pointer that can be chained with builder methods to
// set multiple configuration values inline without using pointers.
// NewConfig returns a new Config pointer that can be chained with builder
// methods to set multiple configuration values inline without using pointers.
//
// sess := session.New(aws.NewConfig().WithRegion("us-west-2").WithMaxRetries(10))
// // 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{}
}
@ -254,6 +302,13 @@ func (c *Config) WithS3UseAccelerate(enable bool) *Config {
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 {
@ -340,6 +395,10 @@ func mergeInConfig(dst *Config, other *Config) {
dst.S3UseAccelerate = other.S3UseAccelerate
}
if other.UseDualStack != nil {
dst.UseDualStack = other.UseDualStack
}
if other.EC2MetadataDisableTimeoutOverride != nil {
dst.EC2MetadataDisableTimeoutOverride = other.EC2MetadataDisableTimeoutOverride
}

View File

@ -30,13 +30,22 @@ func NewStaticCredentials(id, secret, token string) *Credentials {
}})
}
// 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
}
s.Value.ProviderName = StaticProviderName
if len(s.Value.ProviderName) == 0 {
s.Value.ProviderName = StaticProviderName
}
return s.Value, nil
}

View 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
}

View File

@ -90,12 +90,14 @@ func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credenti
Providers: []credentials.Provider{
&credentials.EnvProvider{},
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
remoteCredProvider(*cfg, handlers),
RemoteCredProvider(*cfg, handlers),
},
})
}
func remoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
// 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 {
@ -118,7 +120,7 @@ func ecsCredProvider(cfg aws.Config, handlers request.Handlers, uri string) cred
func ec2RoleProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
endpoint, signingRegion := endpoints.EndpointForRegion(ec2metadata.ServiceName,
aws.StringValue(cfg.Region), true)
aws.StringValue(cfg.Region), true, false)
return &ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.NewClient(cfg, handlers, endpoint, signingRegion),

223
vendor/github.com/aws/aws-sdk-go/aws/session/doc.go generated vendored Normal file
View 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.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,
})
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

View 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
}

View File

@ -1,17 +1,14 @@
// Package session provides a way to create service clients with shared configuration
// and handlers.
//
// Generally this package should be used instead of the `defaults` package.
//
// A session should be used to share configurations and request handlers between multiple
// service clients. When service clients need specific configuration aws.Config can be
// used to provide additional configuration directly to the service client.
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/request"
"github.com/aws/aws-sdk-go/private/endpoints"
@ -21,36 +18,199 @@ import (
// 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.
// 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 Configs or Handlers. The session is safe to be read
// concurrently, but it should not be written to concurrently.
// 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.
//
// Example:
// // Create a session with the default config and request handlers.
// sess := session.New()
// 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 occured while
// loading the session. Use NewSession to get the error when creating the
// session.
//
// // Create a session with a custom region
// sess := session.New(&aws.Config{Region: aws.String("us-east-1")})
// 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/config). Values set in both the
// shared config, and shared credentials will be taken from the shared
// credentials file.
//
// // Create a session, and add additional handlers for all service
// // clients created with the session to inherit. Adds logging handler.
// sess := session.New()
// 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: Use NewSession functiions 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 occuring 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/config). 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 specifing 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 relevent.
//
// 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/config). 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",
// })
//
// // Create a S3 client instance from a session
// sess := session.New()
// svc := s3.New(sess)
func New(cfgs ...*aws.Config) *Session {
// // 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) {
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()
@ -72,6 +232,115 @@ func New(cfgs ...*aws.Config) *Session {
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)
@ -80,12 +349,11 @@ func initHandlers(s *Session) {
}
}
// Copy creates and returns a copy of the current session, coping the config
// 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.
// on top of the Session's copied config.
//
// Example:
// // Create a copy of the current session, configured for the us-west-2 region.
// // 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{
@ -101,15 +369,15 @@ func (s *Session) Copy(cfgs ...*aws.Config) *Session {
// 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.
//
// Example:
// sess := session.New()
// s3.New(sess)
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
s = s.Copy(cfgs...)
endpoint, signingRegion := endpoints.NormalizeEndpoint(
aws.StringValue(s.Config.Endpoint), serviceName,
aws.StringValue(s.Config.Region), aws.BoolValue(s.Config.DisableSSL))
aws.StringValue(s.Config.Endpoint),
serviceName,
aws.StringValue(s.Config.Region),
aws.BoolValue(s.Config.DisableSSL),
aws.BoolValue(s.Config.UseDualStack),
)
return client.Config{
Config: s.Config,

View File

@ -0,0 +1,294 @@
package session
import (
"fmt"
"os"
"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 {
if _, err := os.Stat(filename); os.IsNotExist(err) {
// Trim files from the list that don't exist.
continue
}
f, err := ini.Load(filename)
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)
}

View File

@ -545,7 +545,7 @@ func (ctx *signingCtx) buildBodyDigest() {
} else {
hash = hex.EncodeToString(makeSha256Reader(ctx.Body))
}
if ctx.ServiceName == "s3" {
if ctx.ServiceName == "s3" || ctx.ServiceName == "glacier" {
ctx.Request.Header.Set("X-Amz-Content-Sha256", hash)
}
}

View File

@ -5,4 +5,4 @@ package aws
const SDKName = "aws-sdk-go"
// SDKVersion is the version of this SDK
const SDKVersion = "1.2.7"
const SDKVersion = "1.4.6"

View File

@ -14,9 +14,9 @@ import (
// normalized endpoint and signing region. If the endpoint is not an empty string
// the service name and region will be used to look up the service's API endpoint.
// If the endpoint is provided the scheme will be added if it is not present.
func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL bool) (normEndpoint, signingRegion string) {
func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL, useDualStack bool) (normEndpoint, signingRegion string) {
if endpoint == "" {
return EndpointForRegion(serviceName, region, disableSSL)
return EndpointForRegion(serviceName, region, disableSSL, useDualStack)
}
return AddScheme(endpoint, disableSSL), ""
@ -24,12 +24,17 @@ func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL bool) (n
// EndpointForRegion returns an endpoint and its signing region for a service and region.
// if the service and region pair are not found endpoint and signingRegion will be empty.
func EndpointForRegion(svcName, region string, disableSSL bool) (endpoint, signingRegion string) {
func EndpointForRegion(svcName, region string, disableSSL, useDualStack bool) (endpoint, signingRegion string) {
dualStackField := ""
if useDualStack {
dualStackField = "/dualstack"
}
derivedKeys := []string{
region + "/" + svcName,
region + "/*",
"*/" + svcName,
"*/*",
region + "/" + svcName + dualStackField,
region + "/*" + dualStackField,
"*/" + svcName + dualStackField,
"*/*" + dualStackField,
}
for _, key := range derivedKeys {

View File

@ -65,6 +65,9 @@
"*/s3": {
"endpoint": "s3-{region}.amazonaws.com"
},
"*/s3/dualstack": {
"endpoint": "s3.dualstack.{region}.amazonaws.com"
},
"us-east-1/s3": {
"endpoint": "s3.amazonaws.com"
},

View File

@ -48,6 +48,9 @@ var endpointsMap = endpointStruct{
"*/s3": {
Endpoint: "s3-{region}.amazonaws.com",
},
"*/s3/dualstack": {
Endpoint: "s3.dualstack.{region}.amazonaws.com",
},
"*/sts": {
Endpoint: "sts.amazonaws.com",
SigningRegion: "us-east-1",

View File

@ -1,4 +1,4 @@
// Package ec2query provides serialisation of AWS EC2 requests and responses.
// Package ec2query provides serialization of AWS EC2 requests and responses.
package ec2query
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/ec2.json build_test.go

View File

@ -1,4 +1,4 @@
// Package jsonutil provides JSON serialisation of AWS requests and responses.
// Package jsonutil provides JSON serialization of AWS requests and responses.
package jsonutil
import (
@ -160,7 +160,7 @@ func (sv sortedValues) Less(i, j int) bool { return sv[i].String() < sv[j].Strin
func buildMap(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
buf.WriteString("{")
var sv sortedValues = value.MapKeys()
sv := sortedValues(value.MapKeys())
sort.Sort(sv)
for i, k := range sv {

View File

@ -1,4 +1,4 @@
// Package jsonrpc provides JSON RPC utilities for serialisation of AWS
// Package jsonrpc provides JSON RPC utilities for serialization of AWS
// requests and responses.
package jsonrpc

View File

@ -1,4 +1,4 @@
// Package query provides serialisation of AWS query requests, and responses.
// Package query provides serialization of AWS query requests, and responses.
package query
//go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/query.json build_test.go

View File

@ -1,4 +1,4 @@
// Package restxml provides RESTful XML serialisation of AWS
// Package restxml provides RESTful XML serialization of AWS
// requests and responses.
package restxml

View File

@ -1,4 +1,4 @@
// Package xmlutil provides XML serialisation of AWS requests and responses.
// Package xmlutil provides XML serialization of AWS requests and responses.
package xmlutil
import (

View File

@ -31,7 +31,12 @@
//
// Marshal Go value type for DynamoDB.PutItem:
//
// sess := session.New()
// sess, err := session.NewSession()
// if err != nil {
// fmt.Println("Failed create session", err)
// return
// }
//
// svc := dynamodb.New(sess)
// item, err := dynamodbattribute.MarshalMap(r)
// if err != nil {

View File

@ -9,7 +9,7 @@ import (
"github.com/aws/aws-sdk-go/service/dynamodb"
)
// A Marshaler is an interface to provide custom marshalling of Go value types
// A Marshaler is an interface to provide custom marshaling of Go value types
// to AttributeValues. Use this to provide custom logic determining how a
// Go Value type should be marshaled.
//

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,11 @@ func fillPresignedURL(r *request.Request) {
clientInfo := r.ClientInfo
clientInfo.Endpoint, clientInfo.SigningRegion = endpoints.EndpointForRegion(
clientInfo.ServiceName, aws.StringValue(cfg.Region), aws.BoolValue(cfg.DisableSSL))
clientInfo.ServiceName,
aws.StringValue(cfg.Region),
aws.BoolValue(cfg.DisableSSL),
aws.BoolValue(cfg.UseDualStack),
)
// Presign a CopySnapshot request with modified params
req := request.New(*cfg, clientInfo, r.Handlers, r.Retryer, r.Operation, newParams, r.Data)

View File

@ -7985,7 +7985,9 @@ type CreateGroupInput struct {
//
// The regex pattern (http://wikipedia.org/wiki/regex) for this parameter is
// a string of characters consisting of upper and lowercase alphanumeric characters
// with no spaces. You can also include any of the following characters: =,.@-
// with no spaces. You can also include any of the following characters: =,.@-.
// The group name must be unique within the account. Group names are not distinguished
// by case. For example, you cannot create groups named both "ADMINS" and "admins".
GroupName *string `min:"1" type:"string" required:"true"`
// The path to the group. For more information about paths, see IAM Identifiers
@ -8505,7 +8507,9 @@ type CreateRoleInput struct {
//
// The regex pattern (http://wikipedia.org/wiki/regex) for this parameter is
// a string of characters consisting of upper and lowercase alphanumeric characters
// with no spaces. You can also include any of the following characters: =,.@-
// with no spaces. You can also include any of the following characters: =,.@-.
// Role names are not distinguished by case. For example, you cannot create
// roles named both "PRODROLE" and "prodrole".
RoleName *string `min:"1" type:"string" required:"true"`
}
@ -8654,7 +8658,9 @@ type CreateUserInput struct {
//
// The regex pattern (http://wikipedia.org/wiki/regex) for this parameter is
// a string of characters consisting of upper and lowercase alphanumeric characters
// with no spaces. You can also include any of the following characters: =,.@-
// with no spaces. You can also include any of the following characters: =,.@-.
// User names are not distinguished by case. For example, you cannot create
// users named both "TESTUSER" and "testuser".
UserName *string `min:"1" type:"string" required:"true"`
}

View File

@ -1242,7 +1242,7 @@ func (c *S3) GetBucketReplicationRequest(input *GetBucketReplicationInput) (req
return
}
// Deprecated, see the GetBucketReplicationConfiguration operation.
// Returns the replication configuration of a bucket.
func (c *S3) GetBucketReplication(input *GetBucketReplicationInput) (*GetBucketReplicationOutput, error) {
req, out := c.GetBucketReplicationRequest(input)
err := req.Send()

View File

@ -37,6 +37,14 @@ var accelerateOpBlacklist = operationBlacklist{
func updateEndpointForS3Config(r *request.Request) {
forceHostStyle := aws.BoolValue(r.Config.S3ForcePathStyle)
accelerate := aws.BoolValue(r.Config.S3UseAccelerate)
useDualStack := aws.BoolValue(r.Config.UseDualStack)
if useDualStack && accelerate {
r.Error = awserr.New("InvalidParameterException",
fmt.Sprintf("configuration aws.Config.UseDualStack is not compatible with aws.Config.Accelerate"),
nil)
return
}
if accelerate && accelerateOpBlacklist.Continue(r) {
if forceHostStyle {

View File

@ -23,7 +23,7 @@ func unmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()
defer io.Copy(ioutil.Discard, r.HTTPResponse.Body)
// Bucket exists in a differnt region, and request needs
// Bucket exists in a different region, and request needs
// to be made to the correct region.
if r.HTTPResponse.StatusCode == http.StatusMovedPermanently {
r.Error = awserr.NewRequestFailure(

View File

@ -215,13 +215,14 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
// returned by the operation have the permissions that are defined in the access
// policy of the role that is being assumed. If you pass a policy to this operation,
// the temporary security credentials that are returned by the operation have
// the permissions that are allowed by both the access policy of the role that
// is being assumed, and the policy that you pass. This gives you a way to
// further restrict the permissions for the resulting temporary security credentials.
// You cannot use the passed policy to grant permissions that are in excess
// of those allowed by the access policy of the role that is being assumed.
// For more information, see Permissions for AssumeRole, AssumeRoleWithSAML,
// and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html)
// the permissions that are allowed by the intersection of both the access policy
// of the role that is being assumed, and the policy that you pass. This means
// that both policies must grant the permission for the action to be allowed.
// This gives you a way to further restrict the permissions for the resulting
// temporary security credentials. You cannot use the passed policy to grant
// permissions that are in excess of those allowed by the access policy of the
// role that is being assumed. For more information, see Permissions for AssumeRole,
// AssumeRoleWithSAML, and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html)
// in the IAM User Guide.
//
// Before your application can call AssumeRoleWithSAML, you must configure
@ -743,6 +744,14 @@ type AssumeRoleInput struct {
// The duration, in seconds, of the role session. The value can range from 900
// seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set
// to 3600 seconds.
//
// This is separate from the duration of a console session that you might
// request using the returned credentials. The request to the federation endpoint
// for a console sign-in token takes a SessionDuration parameter that specifies
// the maximum length of the console session, separately from the DurationSeconds
// parameter on this API. For more information, see Creating a URL that Enables
// Federated Users to Access the AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html)
// in the IAM User Guide.
DurationSeconds *int64 `min:"900" type:"integer"`
// A unique identifier that is used by third parties when assuming roles in
@ -757,7 +766,8 @@ type AssumeRoleInput struct {
//
// The format for this parameter, as described by its regex pattern, is a string
// of characters consisting of upper- and lower-case alphanumeric characters
// with no spaces. You can also include any of the following characters: =,.@:\/-
// with no spaces. You can also include underscores or any of the following
// characters: =,.@:\/-
ExternalId *string `min:"2" type:"string"`
// An IAM policy in JSON format.
@ -801,7 +811,8 @@ type AssumeRoleInput struct {
//
// The format for this parameter, as described by its regex pattern, is a string
// of characters consisting of upper- and lower-case alphanumeric characters
// with no spaces. You can also include any of the following characters: =,.@-
// with no spaces. You can also include underscores or any of the following
// characters: =,.@-
RoleSessionName *string `min:"2" type:"string" required:"true"`
// The identification number of the MFA device that is associated with the user
@ -812,7 +823,8 @@ type AssumeRoleInput struct {
//
// The format for this parameter, as described by its regex pattern, is a string
// of characters consisting of upper- and lower-case alphanumeric characters
// with no spaces. You can also include any of the following characters: =,.@-
// with no spaces. You can also include underscores or any of the following
// characters: =,.@-
SerialNumber *string `min:"9" type:"string"`
// The value provided by the MFA device, if the trust policy of the role being
@ -918,8 +930,13 @@ type AssumeRoleWithSAMLInput struct {
// response's SessionNotOnOrAfter value. The actual expiration time is whichever
// value is shorter.
//
// The maximum duration for a session is 1 hour, and the minimum duration
// is 15 minutes, even if values outside this range are specified.
// This is separate from the duration of a console session that you might
// request using the returned credentials. The request to the federation endpoint
// for a console sign-in token takes a SessionDuration parameter that specifies
// the maximum length of the console session, separately from the DurationSeconds
// parameter on this API. For more information, see Enabling SAML 2.0 Federated
// Users to Access the AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-saml.html)
// in the IAM User Guide.
DurationSeconds *int64 `min:"900" type:"integer"`
// An IAM policy in JSON format.
@ -1078,6 +1095,14 @@ type AssumeRoleWithWebIdentityInput struct {
// The duration, in seconds, of the role session. The value can range from 900
// seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set
// to 3600 seconds.
//
// This is separate from the duration of a console session that you might
// request using the returned credentials. The request to the federation endpoint
// for a console sign-in token takes a SessionDuration parameter that specifies
// the maximum length of the console session, separately from the DurationSeconds
// parameter on this API. For more information, see Creating a URL that Enables
// Federated Users to Access the AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html)
// in the IAM User Guide.
DurationSeconds *int64 `min:"900" type:"integer"`
// An IAM policy in JSON format.
@ -1125,7 +1150,8 @@ type AssumeRoleWithWebIdentityInput struct {
//
// The format for this parameter, as described by its regex pattern, is a string
// of characters consisting of upper- and lower-case alphanumeric characters
// with no spaces. You can also include any of the following characters: =,.@-
// with no spaces. You can also include underscores or any of the following
// characters: =,.@-
RoleSessionName *string `min:"2" type:"string" required:"true"`
// The OAuth 2.0 access token or OpenID Connect ID token that is provided by
@ -1432,7 +1458,8 @@ type GetFederationTokenInput struct {
//
// The format for this parameter, as described by its regex pattern, is a string
// of characters consisting of upper- and lower-case alphanumeric characters
// with no spaces. You can also include any of the following characters: =,.@-
// with no spaces. You can also include underscores or any of the following
// characters: =,.@-
Name *string `min:"2" type:"string" required:"true"`
// An IAM policy in JSON format that is passed with the GetFederationToken call
@ -1556,7 +1583,8 @@ type GetSessionTokenInput struct {
//
// The format for this parameter, as described by its regex pattern, is a string
// of characters consisting of upper- and lower-case alphanumeric characters
// with no spaces. You can also include any of the following characters: =,.@-
// with no spaces. You can also include underscores or any of the following
// characters: =,.@-
SerialNumber *string `min:"9" type:"string"`
// The value provided by the MFA device, if MFA is required. If any policy requires

View File

@ -4,7 +4,7 @@
// Original code is based on code by RogerV in the golang-nuts thread:
// https://groups.google.com/group/golang-nuts/browse_thread/thread/40cc41e9d9fc9247
// +build darwin freebsd linux netbsd openbsd solaris
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package speakeasy

View File

@ -0,0 +1,28 @@
Copyright (c) 2016, Circonus, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name Circonus, Inc. nor the names
of its contributors may be used to endorse or promote products
derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -163,7 +163,7 @@ import (
func main() {
cmc := &cgm.Config{}
cmc.CheckManager.API.TokenKey = os.Getenv("CIRCONUS_API_TOKEN")
metrics, err := cgm.NewCirconusMetrics(cmc)
if err != nil {
panic(err)
@ -177,3 +177,5 @@ func main() {
}
```
Unless otherwise noted, the source files are distributed under the BSD-style license found in the LICENSE file.

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package api provides methods for interacting with the Circonus API
package api
@ -152,36 +156,45 @@ func (a *API) apiCall(reqMethod string, reqPath string, data []byte) ([]byte, er
req.Header.Add("X-Circonus-Auth-Token", string(a.key))
req.Header.Add("X-Circonus-App-Name", string(a.app))
// keep last HTTP error in the event of retry failure
var lastHTTPError error
retryPolicy := func(resp *http.Response, err error) (bool, error) {
if err != nil {
lastHTTPError = err
return true, err
}
// Check the response code. We retry on 500-range responses to allow
// the server time to recover, as 500's are typically not permanent
// errors and may relate to outages on the server side. This will catch
// invalid response codes as well, like 0 and 999.
if resp.StatusCode == 0 || resp.StatusCode >= 500 {
defer resp.Body.Close()
body, readErr := ioutil.ReadAll(resp.Body)
if readErr != nil {
lastHTTPError = fmt.Errorf("- last HTTP error: %d %+v", resp.StatusCode, readErr)
} else {
lastHTTPError = fmt.Errorf("- last HTTP error: %d %s", resp.StatusCode, string(body))
}
return true, nil
}
return false, nil
}
client := retryablehttp.NewClient()
client.RetryWaitMin = minRetryWait
client.RetryWaitMax = maxRetryWait
client.RetryMax = maxRetries
client.Logger = a.Log
client.CheckRetry = retryPolicy
resp, err := client.Do(req)
if err != nil {
stdClient := &http.Client{}
dataReader.Seek(0, 0)
stdRequest, _ := http.NewRequest(reqMethod, reqURL, dataReader)
stdRequest.Header.Add("Accept", "application/json")
stdRequest.Header.Add("X-Circonus-Auth-Token", string(a.key))
stdRequest.Header.Add("X-Circonus-App-Name", string(a.app))
res, errSC := stdClient.Do(stdRequest)
if errSC != nil {
return nil, fmt.Errorf("[ERROR] fetching %s: %s", reqURL, errSC)
if lastHTTPError != nil {
return nil, fmt.Errorf("[ERROR] fetching: %+v %+v", err, lastHTTPError)
}
if res != nil && res.Body != nil {
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
if a.Debug {
a.Log.Printf("[DEBUG] %v\n", string(body))
}
return nil, fmt.Errorf("[ERROR] %s", string(body))
}
return nil, fmt.Errorf("[ERROR] fetching %s: %s", reqURL, err)
return nil, fmt.Errorf("[ERROR] fetching %s: %+v", reqURL, err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package api
import (

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package api
import (

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package api
import (

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package checkmgr
import (

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package checkmgr
import (

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package checkmgr
import (

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package checkmgr provides a check management interace to circonus-gometrics
package checkmgr

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package checkmgr
import (

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package circonusgometrics provides instrumentation for your applications in the form
// of counters, gauges and histograms and allows you to publish them to
// Circonus

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package circonusgometrics
// A Counter is a monotonically increasing unsigned integer.

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package circonusgometrics
// A Gauge is an instantaneous measurement of a value.

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package circonusgometrics
import (

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package circonusgometrics
import (

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package circonusgometrics
// A Text metric is an arbitrary string

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package circonusgometrics
import (

View File

@ -1,3 +1,7 @@
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package circonusgometrics
import (

View File

@ -8,10 +8,11 @@ package client
import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
"reflect"
"runtime"
time "time"
codec1978 "github.com/ugorji/go/codec"
)
const (

View File

@ -191,6 +191,10 @@ type SetOptions struct {
// Dir specifies whether or not this Node should be created as a directory.
Dir bool
// NoValueOnSuccess specifies whether the response contains the current value of the Node.
// If set, the response will only contain the current value when the request fails.
NoValueOnSuccess bool
}
type GetOptions struct {
@ -335,6 +339,7 @@ func (k *httpKeysAPI) Set(ctx context.Context, key, val string, opts *SetOptions
act.TTL = opts.TTL
act.Refresh = opts.Refresh
act.Dir = opts.Dir
act.NoValueOnSuccess = opts.NoValueOnSuccess
}
doCtx := ctx
@ -523,15 +528,16 @@ func (w *waitAction) HTTPRequest(ep url.URL) *http.Request {
}
type setAction struct {
Prefix string
Key string
Value string
PrevValue string
PrevIndex uint64
PrevExist PrevExistType
TTL time.Duration
Refresh bool
Dir bool
Prefix string
Key string
Value string
PrevValue string
PrevIndex uint64
PrevExist PrevExistType
TTL time.Duration
Refresh bool
Dir bool
NoValueOnSuccess bool
}
func (a *setAction) HTTPRequest(ep url.URL) *http.Request {
@ -565,6 +571,9 @@ func (a *setAction) HTTPRequest(ep url.URL) *http.Request {
if a.Refresh {
form.Add("refresh", "true")
}
if a.NoValueOnSuccess {
params.Set("noValueOnSuccess", strconv.FormatBool(a.NoValueOnSuccess))
}
u.RawQuery = params.Encode()
body := strings.NewReader(form.Encode())

View File

@ -14,6 +14,20 @@
package client
import (
"regexp"
)
var (
roleNotFoundRegExp *regexp.Regexp
userNotFoundRegExp *regexp.Regexp
)
func init() {
roleNotFoundRegExp = regexp.MustCompile("auth: Role .* does not exist.")
userNotFoundRegExp = regexp.MustCompile("auth: User .* does not exist.")
}
// IsKeyNotFound returns true if the error code is ErrorCodeKeyNotFound.
func IsKeyNotFound(err error) bool {
if cErr, ok := err.(Error); ok {
@ -21,3 +35,19 @@ func IsKeyNotFound(err error) bool {
}
return false
}
// IsRoleNotFound returns true if the error means role not found of v2 API.
func IsRoleNotFound(err error) bool {
if ae, ok := err.(authError); ok {
return roleNotFoundRegExp.MatchString(ae.Message)
}
return false
}
// IsUserNotFound returns true if the error means user not found of v2 API.
func IsUserNotFound(err error) bool {
if ae, ok := err.(authError); ok {
return userNotFoundRegExp.MatchString(ae.Message)
}
return false
}

View File

@ -96,3 +96,26 @@ func Exist(name string) bool {
_, err := os.Stat(name)
return err == nil
}
// ZeroToEnd zeros a file starting from SEEK_CUR to its SEEK_END. May temporarily
// shorten the length of the file.
func ZeroToEnd(f *os.File) error {
// TODO: support FALLOC_FL_ZERO_RANGE
off, err := f.Seek(0, os.SEEK_CUR)
if err != nil {
return err
}
lenf, lerr := f.Seek(0, os.SEEK_END)
if lerr != nil {
return lerr
}
if err = f.Truncate(off); err != nil {
return err
}
// make sure blocks remain allocated
if err = Preallocate(f, lenf, true); err != nil {
return err
}
_, err = f.Seek(off, os.SEEK_SET)
return err
}

View File

@ -67,6 +67,9 @@ type TLSInfo struct {
TrustedCAFile string
ClientCertAuth bool
// ServerName ensures the cert matches the given host in case of discovery / virtual hosting
ServerName string
selfCert bool
// parseFunc exists to simplify testing. Typically, parseFunc
@ -167,6 +170,7 @@ func (info TLSInfo) baseConfig() (*tls.Config, error) {
cfg := &tls.Config{
Certificates: []tls.Certificate{*tlsCert},
MinVersion: tls.VersionTLS12,
ServerName: info.ServerName,
}
return cfg, nil
}
@ -218,7 +222,7 @@ func (info TLSInfo) ClientConfig() (*tls.Config, error) {
return nil, err
}
} else {
cfg = &tls.Config{}
cfg = &tls.Config{ServerName: info.ServerName}
}
CAFiles := info.cafiles()
@ -227,6 +231,8 @@ func (info TLSInfo) ClientConfig() (*tls.Config, error) {
if err != nil {
return nil, err
}
// if given a CA, trust any host with a cert signed by the CA
cfg.ServerName = ""
}
if info.selfCert {

View File

@ -35,7 +35,7 @@ func NewTimeoutTransport(info TLSInfo, dialtimeoutd, rdtimeoutd, wtimeoutd time.
// it should not be put back to http transport as an idle connection for future usage.
tr.MaxIdleConnsPerHost = -1
} else {
// allow more idle connections between peers to avoid unncessary port allocation.
// allow more idle connections between peers to avoid unnecessary port allocation.
tr.MaxIdleConnsPerHost = 1024
}

49
vendor/github.com/coreos/etcd/pkg/transport/tls.go generated vendored Normal file
View File

@ -0,0 +1,49 @@
// Copyright 2016 The etcd Authors
//
// 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 transport
import (
"fmt"
"strings"
"time"
)
// ValidateSecureEndpoints scans the given endpoints against tls info, returning only those
// endpoints that could be validated as secure.
func ValidateSecureEndpoints(tlsInfo TLSInfo, eps []string) ([]string, error) {
t, err := NewTransport(tlsInfo, 5*time.Second)
if err != nil {
return nil, err
}
var errs []string
var endpoints []string
for _, ep := range eps {
if !strings.HasPrefix(ep, "https://") {
errs = append(errs, fmt.Sprintf("%q is insecure", ep))
continue
}
conn, cerr := t.Dial("tcp", ep[len("https://"):])
if cerr != nil {
errs = append(errs, fmt.Sprintf("%q failed to dial (%v)", ep, cerr))
continue
}
conn.Close()
endpoints = append(endpoints, ep)
}
if len(errs) != 0 {
err = fmt.Errorf("%s", strings.Join(errs, ","))
}
return endpoints, err
}

View File

@ -64,7 +64,8 @@ func NewTransport(info TLSInfo, dialtimeoutd time.Duration) (*http.Transport, er
}
func (urt *unixTransport) RoundTrip(req *http.Request) (*http.Response, error) {
req2 := *req
req2.URL.Scheme = strings.Replace(req.URL.Scheme, "unix", "http", 1)
url := *req.URL
req.URL = &url
req.URL.Scheme = strings.Replace(req.URL.Scheme, "unix", "http", 1)
return urt.Transport.RoundTrip(req)
}

View File

@ -558,7 +558,10 @@ func (s *Struct) nested(val reflect.Value) interface{} {
// TODO(arslan): should this be optional?
// do not iterate of non struct types, just pass the value. Ie: []int,
// []string, co... We only iterate further if it's a struct.
if val.Type().Elem().Kind() != reflect.Struct {
// i.e []foo or []*foo
if val.Type().Elem().Kind() != reflect.Struct &&
!(val.Type().Elem().Kind() == reflect.Ptr &&
val.Type().Elem().Elem().Kind() == reflect.Struct) {
finalVal = val.Interface()
break
}

View File

@ -70,6 +70,8 @@ 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
@ -85,7 +87,24 @@ key1, err := cfg.GetKey("Key")
key2, err := cfg.GetKey("KeY")
```
If you want to give more advanced load options, use `LoadSources` and take a look at [`LoadOptions`](https://github.com/go-ini/ini/blob/v1.16.1/ini.go#L156).
#### 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
@ -512,8 +531,8 @@ Why not?
```go
type Embeded struct {
Dates []time.Time `delim:"|"`
Places []string
None []int
Places []string `ini:"places,omitempty"`
None []int `ini:",omitempty"`
}
type Author struct {
@ -548,8 +567,7 @@ GPA = 2.8
[Embeded]
Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00
Places = HangZhou,Boston
None =
places = HangZhou,Boston
```
#### Name Mapper
@ -583,6 +601,26 @@ func main() {
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:

View File

@ -63,6 +63,8 @@ cfg, err := ini.LooseLoad("filename", "filename_404")
更牛逼的是,当那些之前不存在的文件在重新调用 `Reload` 方法的时候突然出现了,那么它们会被正常加载。
#### 忽略键名的大小写
有时候分区和键的名称大小写混合非常烦人,这个时候就可以通过 `InsensitiveLoad` 将所有分区和键名在读取里强制转换为小写:
```go
@ -78,7 +80,24 @@ key1, err := cfg.GetKey("Key")
key2, err := cfg.GetKey("KeY")
```
如果您想要更加自定义的加载选项,可以使用 `LoadSources` 方法并参见 [`LoadOptions`](https://github.com/go-ini/ini/blob/v1.16.1/ini.go#L156)。
#### 类似 MySQL 配置中的布尔值键
MySQL 的配置文件中会出现没有具体值的布尔类型的键:
```ini
[mysqld]
...
skip-host-cache
skip-name-resolve
```
默认情况下这被认为是缺失值而无法完成解析,但可以通过高级的加载选项对它们进行处理:
```go
cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
```
这些键的值永远为 `true`,且在保存到文件时也只会输出键名。
### 操作分区Section
@ -503,8 +522,8 @@ p := &Person{
```go
type Embeded struct {
Dates []time.Time `delim:"|"`
Places []string
None []int
Places []string `ini:"places,omitempty"`
None []int `ini:",omitempty"`
}
type Author struct {
@ -539,8 +558,7 @@ GPA = 2.8
[Embeded]
Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00
Places = HangZhou,Boston
None =
places = HangZhou,Boston
```
#### 名称映射器Name Mapper
@ -574,6 +592,26 @@ func main() {
使用函数 `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` 的值。
#### 映射/反射的其它说明
任何嵌入的结构都会被默认认作一个不同的分区,并且不会自动产生所谓的父子分区关联:

32
vendor/github.com/go-ini/ini/error.go generated vendored Normal file
View 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)
}

12
vendor/github.com/go-ini/ini/ini.go generated vendored
View File

@ -36,7 +36,7 @@ const (
// Maximum allowed depth when recursively substituing variable names.
_DEPTH_VALUES = 99
_VERSION = "1.18.0"
_VERSION = "1.21.1"
)
// Version returns current package version literal.
@ -129,6 +129,7 @@ type File struct {
options LoadOptions
NameMapper
ValueMapper
}
// newFile initializes File object with given data sources.
@ -160,6 +161,9 @@ type LoadOptions struct {
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) {
@ -422,7 +426,7 @@ func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) {
}
switch {
case key.isAutoIncr:
case key.isAutoIncrement:
kname = "-"
case strings.ContainsAny(kname, "\"=:"):
kname = "`" + kname + "`"
@ -433,6 +437,10 @@ func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) {
return 0, err
}
if key.isBooleanType {
continue
}
// Write out alignment spaces before "=" sign
if PrettyFormat {
buf.Write(alignSpaces[:alignLength-len(kname)])

18
vendor/github.com/go-ini/ini/key.go generated vendored
View File

@ -23,13 +23,18 @@ import (
// Key represents a key under a section.
type Key struct {
s *Section
Comment string
name string
value string
isAutoIncr bool
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
@ -43,6 +48,9 @@ func (k *Key) Value() string {
// 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
}

View File

@ -111,7 +111,7 @@ func readKeyName(in []byte) (string, int, error) {
// Find key-value delimiter
i := strings.IndexAny(line[pos+startIdx:], "=:")
if i < 0 {
return "", -1, fmt.Errorf("key-value delimiter not found: %s", line)
return "", -1, ErrDelimiterNotFound{line}
}
endIdx = pos + i
return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil
@ -119,7 +119,7 @@ func readKeyName(in []byte) (string, int, error) {
endIdx = strings.IndexAny(line, "=:")
if endIdx < 0 {
return "", -1, fmt.Errorf("key-value delimiter not found: %s", line)
return "", -1, ErrDelimiterNotFound{line}
}
return strings.TrimSpace(line[0:endIdx]), endIdx + 1, nil
}
@ -285,6 +285,17 @@ func (f *File) parse(reader io.Reader) (err error) {
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
}
@ -300,7 +311,7 @@ func (f *File) parse(reader io.Reader) (err error) {
if err != nil {
return err
}
key.isAutoIncr = isAutoIncr
key.isAutoIncrement = isAutoIncr
value, err := p.readValue(line[offset:], f.options.IgnoreContinuation)
if err != nil {

View File

@ -58,7 +58,11 @@ func (s *Section) NewKey(name, val string) (*Key, error) {
}
s.keyList = append(s.keyList, name)
s.keys[name] = &Key{s, "", name, val, false}
s.keys[name] = &Key{
s: s,
name: name,
value: val,
}
s.keysHash[name] = val
return s.keys[name], nil
}

View File

@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"reflect"
"strings"
"time"
"unicode"
)
@ -161,7 +162,8 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri
// 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()
if err == nil {
// Skip zero value
if err == nil && int(durationVal) > 0 {
field.Set(reflect.ValueOf(durationVal))
return nil
}
@ -207,7 +209,8 @@ func (s *Section) mapTo(val reflect.Value) error {
continue
}
fieldName := s.parseFieldName(tpField.Name, tag)
opts := strings.SplitN(tag, ",", 2) // strip off possible omitempty
fieldName := s.parseFieldName(tpField.Name, opts[0])
if len(fieldName) == 0 || !field.CanSet() {
continue
}
@ -323,6 +326,28 @@ func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim
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()
@ -338,13 +363,18 @@ func (s *Section) reflectFrom(val reflect.Value) error {
continue
}
fieldName := s.parseFieldName(tpField.Name, tag)
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.Kind() != reflectTime) {
(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 {
@ -352,7 +382,7 @@ func (s *Section) reflectFrom(val reflect.Value) error {
sec, _ = s.f.NewSection(fieldName)
}
if err = sec.reflectFrom(field); err != nil {
return fmt.Errorf("error reflecting field(%s): %v", fieldName, err)
return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
}
continue
}
@ -363,7 +393,7 @@ func (s *Section) reflectFrom(val reflect.Value) error {
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 fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
}
}

View File

@ -89,7 +89,7 @@ func (c *ControlPaging) Encode() *ber.Packet {
p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Paging)")
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value")
seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(c.PagingSize), "Paging Size"))
seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.PagingSize), "Paging Size"))
cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie")
cookie.Value = c.Cookie
cookie.Data.Write(c.Cookie)
@ -254,19 +254,54 @@ func FindControl(controls []Control, controlType string) Control {
// DecodeControl returns a control read from the given packet, or nil if no recognized control can be made
func DecodeControl(packet *ber.Packet) Control {
ControlType := packet.Children[0].Value.(string)
Criticality := false
var (
ControlType = ""
Criticality = false
value *ber.Packet
)
switch len(packet.Children) {
case 0:
// at least one child is required for control type
return nil
case 1:
// just type, no criticality or value
packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
ControlType = packet.Children[0].Value.(string)
case 2:
packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
ControlType = packet.Children[0].Value.(string)
// Children[1] could be criticality or value (both are optional)
// duck-type on whether this is a boolean
if _, ok := packet.Children[1].Value.(bool); ok {
packet.Children[1].Description = "Criticality"
Criticality = packet.Children[1].Value.(bool)
} else {
packet.Children[1].Description = "Control Value"
value = packet.Children[1]
}
case 3:
packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
ControlType = packet.Children[0].Value.(string)
packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
value := packet.Children[1]
if len(packet.Children) == 3 {
value = packet.Children[2]
packet.Children[1].Description = "Criticality"
Criticality = packet.Children[1].Value.(bool)
packet.Children[2].Description = "Control Value"
value = packet.Children[2]
default:
// more than 3 children is invalid
return nil
}
value.Description = "Control Value"
switch ControlType {
case ControlTypeManageDsaIT:
return NewControlManageDsaIT(Criticality)
case ControlTypePaging:
value.Description += " (Paging)"
c := new(ControlPaging)
@ -341,13 +376,16 @@ func DecodeControl(packet *ber.Packet) Control {
c.Expire = expire
value.Value = c.Expire
return c
default:
c := new(ControlString)
c.ControlType = ControlType
c.Criticality = Criticality
if value != nil {
c.ControlValue = value.Value.(string)
}
return c
}
c := new(ControlString)
c.ControlType = ControlType
c.Criticality = Criticality
c.ControlValue = value.Value.(string)
return c
}
// NewControlString returns a generic control

View File

@ -729,16 +729,19 @@ func (rows *textRows) readRow(dest []driver.Value) error {
func (mc *mysqlConn) readUntilEOF() error {
for {
data, err := mc.readPacket()
// No Err and no EOF Packet
if err == nil && data[0] != iEOF {
continue
}
if err == nil && data[0] == iEOF && len(data) == 5 {
mc.status = readStatus(data[3:])
if err != nil {
return err
}
return err // Err or EOF
switch data[0] {
case iERR:
return mc.handleErrorPacket(data)
case iEOF:
if len(data) == 5 {
mc.status = readStatus(data[3:])
}
return nil
}
}
}

View File

@ -73,3 +73,8 @@ Michael Highstead <highstead@gmail.com>
Sarah Brown <esbie.is@gmail.com>
Caleb Doxsey <caleb@datadoghq.com>
Frederic Hemery <frederic.hemery@datadoghq.com>
Pekka Enberg <penberg@scylladb.com>
Mark M <m.mim95@gmail.com>
Bartosz Burclaf <burclaf@gmail.com>
Marcus King <marcusking01@gmail.com>
Andrew de Andrade <andrew@deandrade.com.br>

View File

@ -201,6 +201,7 @@ The following community maintained tools are known to integrate with gocql:
* [gocassa](https://github.com/hailocab/gocassa) provides query building, adds data binding, and provides easy-to-use "recipe" tables for common query use-cases.
* [gocqltable](https://github.com/kristoiv/gocqltable) is a wrapper around gocql that aims to simplify common operations whilst working the library.
* [gockle](https://github.com/willfaught/gockle) provides simple, mockable interfaces that wrap gocql types
* [scylladb](https://github.com/scylladb/scylla) is a fast Apache Cassandra-compatible NoSQL database
Other Projects
--------------

View File

@ -10,7 +10,7 @@ import (
)
// PoolConfig configures the connection pool used by the driver, it defaults to
// using a round robbin host selection policy and a round robbin connection selection
// using a round-robin host selection policy and a round-robin connection selection
// policy for each host.
type PoolConfig struct {
// HostSelectionPolicy sets the policy for selecting which host to use for a
@ -23,9 +23,9 @@ func (p PoolConfig) buildPool(session *Session) *policyConnPool {
}
type DiscoveryConfig struct {
// If not empty will filter all discoverred hosts to a single Data Centre (default: "")
// If not empty will filter all discovered hosts to a single Data Centre (default: "")
DcFilter string
// If not empty will filter all discoverred hosts to a single Rack (default: "")
// If not empty will filter all discovered hosts to a single Rack (default: "")
RackFilter string
// ignored
Sleep time.Duration
@ -44,8 +44,8 @@ func (d DiscoveryConfig) matchFilter(host *HostInfo) bool {
}
// ClusterConfig is a struct to configure the default cluster implementation
// of gocoql. It has a varity of attributes that can be used to modify the
// behavior to fit the most common use cases. Applications that requre a
// of gocoql. It has a variety of attributes that can be used to modify the
// behavior to fit the most common use cases. Applications that require a
// different setup must implement their own cluster.
type ClusterConfig struct {
Hosts []string // addresses for the initial connections
@ -79,7 +79,7 @@ type ClusterConfig struct {
// receiving a schema change frame. (deault: 60s)
MaxWaitSchemaAgreement time.Duration
// HostFilter will filter all incoming events for host, any which dont pass
// HostFilter will filter all incoming events for host, any which don't pass
// the filter will be ignored. If set will take precedence over any options set
// via Discovery
HostFilter HostFilter
@ -113,7 +113,7 @@ type ClusterConfig struct {
// DisableSkipMetadata will override the internal result metadata cache so that the driver does not
// send skip_metadata for queries, this means that the result will always contain
// the metadata to parse the rows and will not reuse the metadata from the prepared
// staement.
// statement.
//
// See https://issues.apache.org/jira/browse/CASSANDRA-10786
DisableSkipMetadata bool

View File

@ -205,6 +205,22 @@ func ParseConsistency(s string) Consistency {
}
}
// ParseConsistencyWrapper wraps gocql.ParseConsistency to provide an err
// return instead of a panic
func ParseConsistencyWrapper(s string) (consistency Consistency, err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("ParseConsistencyWrapper: %v", r)
}
}
}()
consistency = ParseConsistency(s)
return consistency, nil
}
type SerialConsistency uint16
const (

View File

@ -247,7 +247,7 @@ func (iter *Iter) SliceMap() ([]map[string]interface{}, error) {
}
// MapScan takes a map[string]interface{} and populates it with a row
// That is returned from cassandra.
// that is returned from cassandra.
func (iter *Iter) MapScan(m map[string]interface{}) bool {
if iter.err != nil {
return false

View File

@ -234,7 +234,7 @@ func (h *HostInfo) update(from *HostInfo) {
}
func (h *HostInfo) IsUp() bool {
return h.State() == NodeUp
return h != nil && h.State() == NodeUp
}
func (h *HostInfo) String() string {
@ -272,6 +272,22 @@ func checkSystemLocal(control *controlConn) (bool, error) {
return true, nil
}
// Returns true if we are using system_schema.keyspaces instead of system.schema_keyspaces
func checkSystemSchema(control *controlConn) (bool, error) {
iter := control.query("SELECT * FROM system_schema.keyspaces")
if err := iter.err; err != nil {
if errf, ok := err.(*errorFrame); ok {
if errf.code == errReadFailure {
return false, nil
}
}
return false, err
}
return true, nil
}
func (r *ringDescriber) GetHosts() (hosts []*HostInfo, partitioner string, err error) {
r.mu.Lock()
defer r.mu.Unlock()

View File

@ -1651,6 +1651,9 @@ func unmarshalUDT(info TypeInfo, data []byte, value interface{}) error {
udt := info.(UDTTypeInfo)
for _, e := range udt.Elements {
if len(data) == 0 {
return nil
}
size := readInt(data[:4])
data = data[4:]
@ -1689,6 +1692,9 @@ func unmarshalUDT(info TypeInfo, data []byte, value interface{}) error {
m := *v
for _, e := range udt.Elements {
if len(data) == 0 {
return nil
}
size := readInt(data[:4])
data = data[4:]

View File

@ -13,7 +13,7 @@ import (
"github.com/hailocab/go-hostpool"
)
// cowHostList implements a copy on write host list, its equivilent type is []*HostInfo
// cowHostList implements a copy on write host list, its equivalent type is []*HostInfo
type cowHostList struct {
list atomic.Value
mu sync.Mutex
@ -263,9 +263,6 @@ type tokenAwareHostPolicy struct {
}
func (t *tokenAwareHostPolicy) SetPartitioner(partitioner string) {
t.mu.Lock()
defer t.mu.Unlock()
if t.partitioner != partitioner {
t.fallback.SetPartitioner(partitioner)
t.partitioner = partitioner
@ -278,18 +275,14 @@ func (t *tokenAwareHostPolicy) AddHost(host *HostInfo) {
t.hosts.add(host)
t.fallback.AddHost(host)
t.mu.Lock()
t.resetTokenRing()
t.mu.Unlock()
}
func (t *tokenAwareHostPolicy) RemoveHost(addr string) {
t.hosts.remove(addr)
t.fallback.RemoveHost(addr)
t.mu.Lock()
t.resetTokenRing()
t.mu.Unlock()
}
func (t *tokenAwareHostPolicy) HostUp(host *HostInfo) {
@ -301,6 +294,9 @@ func (t *tokenAwareHostPolicy) HostDown(addr string) {
}
func (t *tokenAwareHostPolicy) resetTokenRing() {
t.mu.Lock()
defer t.mu.Unlock()
if t.partitioner == "" {
// partitioner not yet set
return
@ -377,7 +373,7 @@ func (t *tokenAwareHostPolicy) Pick(qry ExecutableQuery) NextHost {
// // Create host selection policy using a simple host pool
// cluster.PoolConfig.HostSelectionPolicy = HostPoolHostPolicy(hostpool.New(nil))
//
// // Create host selection policy using an epsilon greddy pool
// // Create host selection policy using an epsilon greedy pool
// cluster.PoolConfig.HostSelectionPolicy = HostPoolHostPolicy(
// hostpool.NewEpsilonGreedy(nil, 0, &hostpool.LinearEpsilonValueCalculator{}),
// )
@ -411,18 +407,20 @@ func (r *hostPoolHostPolicy) AddHost(host *HostInfo) {
r.mu.Lock()
defer r.mu.Unlock()
if _, ok := r.hostMap[host.Peer()]; ok {
// If the host addr is present and isn't nil return
if h, ok := r.hostMap[host.Peer()]; ok && h != nil{
return
}
hosts := make([]string, 0, len(r.hostMap)+1)
// otherwise, add the host to the map
r.hostMap[host.Peer()] = host
// and construct a new peer list to give to the HostPool
hosts := make([]string, 0, len(r.hostMap))
for addr := range r.hostMap {
hosts = append(hosts, addr)
}
hosts = append(hosts, host.Peer())
r.hp.SetHosts(hosts)
r.hostMap[host.Peer()] = host
}
func (r *hostPoolHostPolicy) RemoveHost(addr string) {

View File

@ -24,7 +24,7 @@ func (q *queryExecutor) executeQuery(qry ExecutableQuery) (*Iter, error) {
var iter *Iter
for hostResponse := hostIter(); hostResponse != nil; hostResponse = hostIter() {
host := hostResponse.Info()
if !host.IsUp() {
if host == nil || !host.IsUp() {
continue
}

View File

@ -66,6 +66,8 @@ type Session struct {
cfg ClusterConfig
quit chan struct{}
closeMu sync.RWMutex
isClosed bool
}
@ -183,6 +185,8 @@ func NewSession(cfg ClusterConfig) (*Session, error) {
}
}
s.quit = make(chan struct{})
if cfg.ReconnectInterval > 0 {
go s.reconnectDownedHosts(cfg.ReconnectInterval)
}
@ -195,31 +199,46 @@ func NewSession(cfg ClusterConfig) (*Session, error) {
return nil, ErrNoConnectionsStarted
}
s.useSystemSchema = hosts[0].Version().Major >= 3
// If we disable the initial host lookup, we need to still check if the
// cluster is using the newer system schema or not... however, if control
// connection is disable, we really have no choice, so we just make our
// best guess...
if !cfg.disableControlConn && cfg.DisableInitialHostLookup {
newer, _ := checkSystemSchema(s.control)
s.useSystemSchema = newer
} else {
s.useSystemSchema = hosts[0].Version().Major >= 3
}
return s, nil
}
func (s *Session) reconnectDownedHosts(intv time.Duration) {
for !s.Closed() {
time.Sleep(intv)
reconnectTicker := time.NewTicker(intv)
defer reconnectTicker.Stop()
hosts := s.ring.allHosts()
for {
select {
case <-reconnectTicker.C:
hosts := s.ring.allHosts()
// Print session.ring for debug.
if gocqlDebug {
buf := bytes.NewBufferString("Session.ring:")
for _, h := range hosts {
buf.WriteString("[" + h.Peer() + ":" + h.State().String() + "]")
}
log.Println(buf.String())
}
// Print session.ring for debug.
if gocqlDebug {
buf := bytes.NewBufferString("Session.ring:")
for _, h := range hosts {
buf.WriteString("[" + h.Peer() + ":" + h.State().String() + "]")
if h.IsUp() {
continue
}
s.handleNodeUp(net.ParseIP(h.Peer()), h.Port(), true)
}
log.Println(buf.String())
}
for _, h := range hosts {
if h.IsUp() {
continue
}
s.handleNodeUp(net.ParseIP(h.Peer()), h.Port(), true)
case <-s.quit:
return
}
}
}
@ -332,6 +351,10 @@ func (s *Session) Close() {
if s.schemaEvents != nil {
s.schemaEvents.stop()
}
if s.quit != nil {
close(s.quit)
}
}
func (s *Session) Closed() bool {
@ -1141,7 +1164,7 @@ func (iter *Iter) PageState() []byte {
}
// NumRows returns the number of rows in this pagination, it will update when new
// pages are fetcehd, it is not the value of the total number of rows this iter
// pages are fetched, it is not the value of the total number of rows this iter
// will return unless there is only a single page returned.
func (iter *Iter) NumRows() int {
return iter.numRows

View File

@ -54,13 +54,17 @@ Equality is defined in this way:
in a proto3 .proto file, fields are not "set"; specifically,
zero length proto3 "bytes" fields are equal (nil == {}).
- Two repeated fields are equal iff their lengths are the same,
and their corresponding elements are equal (a "bytes" field,
although represented by []byte, is not a repeated field)
and their corresponding elements are equal. Note a "bytes" field,
although represented by []byte, is not a repeated field and the
rule for the scalar fields described above applies.
- Two unset fields are equal.
- Two unknown field sets are equal if their current
encoded state is equal.
- Two extension sets are equal iff they have corresponding
elements that are pairwise equal.
- Two map fields are equal iff their lengths are the same,
and they contain the same set of elements. Zero-length map
fields are equal.
- Every other combination of things are not equal.
The return value is undefined if a and b are not protocol buffers.

View File

@ -500,6 +500,9 @@ func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) {
registeredExtensions := RegisteredExtensions(pb)
emap, mu := epb.extensionsRead()
if emap == nil {
return nil, nil
}
mu.Lock()
defer mu.Unlock()
extensions := make([]*ExtensionDesc, 0, len(emap))

View File

@ -308,7 +308,7 @@ func GetStats() Stats { return stats }
// temporary Buffer and are fine for most applications.
type Buffer struct {
buf []byte // encode/decode byte stream
index int // write point
index int // read point
// pools of basic types to amortize allocation.
bools []bool

View File

@ -844,7 +844,15 @@ func RegisterType(x Message, name string) {
}
// MessageName returns the fully-qualified proto name for the given message type.
func MessageName(x Message) string { return revProtoTypes[reflect.TypeOf(x)] }
func MessageName(x Message) string {
type xname interface {
XXX_MessageName() string
}
if m, ok := x.(xname); ok {
return m.XXX_MessageName()
}
return revProtoTypes[reflect.TypeOf(x)]
}
// MessageType returns the message type (pointer to struct) for a named message.
func MessageType(name string) reflect.Type { return protoTypes[name] }

View File

@ -44,6 +44,9 @@ import (
"unicode/utf8"
)
// Error string emitted when deserializing Any and fields are already set
const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set"
type ParseError struct {
Message string
Line int // 1-based line number
@ -508,8 +511,16 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
if err != nil {
return p.errorf("failed to marshal message of type %q: %v", messageName, err)
}
if fieldSet["type_url"] {
return p.errorf(anyRepeatedlyUnpacked, "type_url")
}
if fieldSet["value"] {
return p.errorf(anyRepeatedlyUnpacked, "value")
}
sv.FieldByName("TypeUrl").SetString(extName)
sv.FieldByName("Value").SetBytes(b)
fieldSet["type_url"] = true
fieldSet["value"] = true
continue
}
@ -781,12 +792,12 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error {
fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem()))
return p.readAny(fv.Index(fv.Len()-1), props)
case reflect.Bool:
// Either "true", "false", 1 or 0.
// true/1/t/True or false/f/0/False.
switch tok.value {
case "true", "1":
case "true", "1", "t", "True":
fv.SetBool(true)
return nil
case "false", "0":
case "false", "0", "f", "False":
fv.SetBool(false)
return nil
}

View File

@ -398,7 +398,7 @@ func (s *AuthorizationsService) DeleteGrant(id int) (*Response, error) {
return s.client.Do(req, nil)
}
// Create an impersonation OAuth token.
// CreateImpersonation creates an impersonation OAuth token.
//
// This requires admin permissions. With the returned Authorization.Token
// you can e.g. create or delete a user's public SSH key. NOTE: creating a
@ -420,7 +420,7 @@ func (s *AuthorizationsService) CreateImpersonation(username string, authReq *Au
return a, resp, err
}
// Delete an impersonation OAuth token.
// DeleteImpersonation deletes an impersonation OAuth token.
//
// NOTE: there can be only one at a time.
//

View File

@ -22,8 +22,8 @@ Some API methods have optional parameters that can be passed. For example:
client := github.NewClient(nil)
// list recently updated repositories for org "github"
opt := &github.RepositoryListByOrgOptions{Sort: "updated"}
// list public repositories for org "github"
opt := &github.RepositoryListByOrgOptions{Type: "public"}
repos, _, err := client.Repositories.ListByOrg("github", opt)
The services of a client divide the API into logical chunks and correspond to

View File

@ -123,8 +123,9 @@ type GollumEvent struct {
Sender *User `json:"sender,omitempty"`
}
// DEPRECATED: IssueActivityEvent represents the payload delivered by Issue webhook
// Use IssuesEvent instead.
// IssueActivityEvent represents the payload delivered by Issue webhook.
//
// Deprecated: Use IssuesEvent instead.
type IssueActivityEvent struct {
Action *string `json:"action,omitempty"`
Issue *Issue `json:"issue,omitempty"`

Some files were not shown because too many files have changed in this diff Show More