This repository has been archived by the owner on Apr 14, 2020. It is now read-only.
/
aws.go
137 lines (121 loc) · 3.57 KB
/
aws.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package aws
import (
"reflect"
"github.com/gravitational/force"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
awssession "github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/gravitational/trace"
)
// Scope returns a new scope with all the functions and structs
// defined, this is the entrypoint into plugin as far as force is concerned
func Scope() (force.Group, error) {
scope := force.WithLexicalScope(nil)
err := force.ImportStructsIntoAST(scope,
reflect.TypeOf(Config{}),
reflect.TypeOf(S3{}),
reflect.TypeOf(Local{}),
)
if err != nil {
return nil, trace.Wrap(err)
}
scope.AddDefinition(force.FunctionName(Copy), &force.NopScope{Func: Copy})
scope.AddDefinition(force.FunctionName(RecursiveCopy), &force.NopScope{Func: RecursiveCopy})
scope.AddDefinition(force.StructName(reflect.TypeOf(Setup{})), &Setup{})
return scope, nil
}
//Namespace is a wrapper around string to namespace a variable in the context
type Namespace string
// Key is a name of the plugin variable
const Key = Namespace("aws")
const (
KeySetup = "Setup"
KeyConfig = "Config"
SchemeS3 = "s3"
)
// Config is an ssh client configuration
type Config struct {
// Region is S3 bucket region
Region string
}
// CheckAndSetDefaults checks and sets default values
func (cfg *Config) CheckAndSetDefaults() (*awssession.Session, error) {
// create an AWS session using default SDK behavior, i.e. it will interpret
// the environment and ~/.aws directory just like an AWS CLI tool would:
sess, err := awssession.NewSessionWithOptions(awssession.Options{
SharedConfigState: awssession.SharedConfigEnable,
})
if err != nil {
return nil, trace.Wrap(err)
}
// override the default environment (region + credentials) with the values
// from the YAML file:
if cfg.Region != "" {
sess.Config.Region = aws.String(cfg.Region)
}
return sess, nil
}
// Plugin is a new logging plugin
type Plugin struct {
cfg Config
sess *awssession.Session
}
// Setup creates new instances of plugins
type Setup struct {
cfg interface{}
}
func (n *Setup) Type() interface{} {
return true
}
// NewInstance returns a new instance of a plugin bound to group
func (n *Setup) NewInstance(group force.Group) (force.Group, interface{}) {
return group, func(cfg interface{}) (force.Action, error) {
return &Setup{
cfg: cfg,
}, nil
}
}
// MarshalCode marshals plugin setup to code
func (n *Setup) MarshalCode(ctx force.ExecutionContext) ([]byte, error) {
call := force.FnCall{
Package: string(Key),
FnName: KeySetup,
Args: []interface{}{n.cfg},
}
return call.MarshalCode(ctx)
}
// Eval sets up logging plugin for the instance group
func (n *Setup) Eval(ctx force.ExecutionContext) (interface{}, error) {
var cfg Config
if err := force.EvalInto(ctx, n.cfg, &cfg); err != nil {
return nil, trace.Wrap(err)
}
sess, err := cfg.CheckAndSetDefaults()
if err != nil {
return nil, trace.Wrap(err)
}
p := &Plugin{
cfg: cfg,
sess: sess,
}
ctx.Process().Group().SetPlugin(Key, p)
return true, nil
}
// ConvertS3Error wraps S3 error and returns trace equivalent
func ConvertS3Error(err error, args ...interface{}) error {
if err == nil {
return nil
}
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case s3.ErrCodeNoSuchKey, s3.ErrCodeNoSuchBucket, s3.ErrCodeNoSuchUpload, "NotFound":
return trace.NotFound(aerr.Error(), args...)
case s3.ErrCodeBucketAlreadyExists, s3.ErrCodeBucketAlreadyOwnedByYou:
return trace.AlreadyExists(aerr.Error(), args...)
default:
return trace.BadParameter(aerr.Error(), args...)
}
}
return err
}