Update readme and docstrings, minor refactors.
This commit is contained in:
+66
-1
@@ -7,6 +7,8 @@ import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -16,6 +18,10 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
securityCredentialsURL = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
||||
)
|
||||
|
||||
// S3 provides a wrapper around your S3 credentials.
|
||||
type S3 struct {
|
||||
AccessKey string
|
||||
@@ -40,6 +46,18 @@ type DeleteInput struct {
|
||||
ObjectKey string
|
||||
}
|
||||
|
||||
// IAMResponse is used by NewUsingIAM to auto
|
||||
// detect the credentials
|
||||
type IAMResponse struct {
|
||||
Code string `json:"Code"`
|
||||
LastUpdated string `json:"LastUpdated"`
|
||||
Type string `json:"Type"`
|
||||
AccessKeyID string `json:"AccessKeyId"`
|
||||
SecretAccessKey string `json:"SecretAccessKey"`
|
||||
Token string `json:"Token"`
|
||||
Expiration string `json:"Expiration"`
|
||||
}
|
||||
|
||||
// New returns an instance of S3.
|
||||
func New(region, accessKey, secretKey string) *S3 {
|
||||
return &S3{
|
||||
@@ -51,6 +69,53 @@ func New(region, accessKey, secretKey string) *S3 {
|
||||
}
|
||||
}
|
||||
|
||||
// NewUsingIAM automatically generates an Instance of S3
|
||||
// using instance metatdata.
|
||||
func NewUsingIAM(region string) (*S3, error) {
|
||||
|
||||
// Get the IAM role
|
||||
resp, err := http.Get(securityCredentialsURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, errors.New(http.StatusText(resp.StatusCode))
|
||||
}
|
||||
|
||||
role, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err = http.Get(securityCredentialsURL + "/" + string(role))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, errors.New(http.StatusText(resp.StatusCode))
|
||||
}
|
||||
|
||||
var jsonResp IAMResponse
|
||||
jsonString, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(jsonString, &jsonResp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &S3{
|
||||
Region: region,
|
||||
AccessKey: jsonResp.AccessKeyID,
|
||||
SecretKey: jsonResp.SecretAccessKey,
|
||||
|
||||
URIFormat: "https://s3.%s.amazonaws.com/%s",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func detectFileSize(body multipart.File) int64 {
|
||||
switch r := body.(type) {
|
||||
case io.Seeker:
|
||||
@@ -133,7 +198,7 @@ func (s3 *S3) FileUpload(u UploadInput) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FileDelete makes a POST call with the file written as multipart
|
||||
// FileDelete makes a DELETE call with the file written as multipart
|
||||
// and on successful upload, checks for 204 No Content.
|
||||
func (s3 *S3) FileDelete(u DeleteInput) error {
|
||||
url := fmt.Sprintf(
|
||||
|
||||
Reference in New Issue
Block a user