@@ -22,17 +22,134 @@ using DataStructures: OrderedDict
22
22
using JSON
23
23
using LazyJSON
24
24
25
+ # NOTE: This needs to be defined before AWSConfig. Methods defined on AWSCredentials are
26
+ # in src/AWSCredentials.jl.
27
+ """
28
+ AWSCredentials
29
+
30
+ A type which holds AWS credentials.
31
+ When you interact with AWS, you specify your
32
+ [AWS Security Credentials](http://docs.aws.amazon.com/general/latest/gr/aws-security-credentials.html)
33
+ to verify who you are and whether you have permission to access the resources that you are
34
+ requesting. AWS uses the security credentials to authenticate and authorize your requests.
35
+
36
+ The fields `access_key_id` and `secret_key` hold the access keys used to authenticate API
37
+ requests (see [Creating, Modifying, and Viewing Access
38
+ Keys](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey)).
39
+
40
+ [Temporary Security Credentials](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html)
41
+ require the extra session `token` field.
42
+
43
+ The `user_arn` and `account_number` fields are used to cache the result of the
44
+ [`aws_user_arn`](@ref) and [`aws_account_number`](@ref) functions.
25
45
46
+ The `AWSCredentials()` constructor tries to load local credentials from:
47
+
48
+ * `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`
49
+ [environment variables](http://docs.aws.amazon.com/cli/latest/userguide/cli-environment.html),
50
+ * [`~/.aws/credentials`](http://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html), or
51
+ * [EC2 Instance Credentials](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#instance-metadata-security-credentials).
52
+
53
+ To specify the profile to use from `~/.aws/credentials`, do, for example,
54
+ `AWSCredentials(profile="profile-name")`.
55
+
56
+ A `~/.aws/credentials` file can be created using the
57
+ [AWS CLI](https://aws.amazon.com/cli/) command `aws configrue`.
58
+ Or it can be created manually:
59
+
60
+ ```ini
61
+ [default]
62
+ aws_access_key_id = AKIAXXXXXXXXXXXXXXXX
63
+ aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
64
+ ```
65
+
66
+ If your `~/.aws/credentials` file contains multiple profiles you can pass the
67
+ profile name as a string to the `profile` keyword argument (`nothing` by
68
+ default) or select a profile by setting the `AWS_PROFILE` environment variable.
26
69
"""
27
- Most `AWSCore` functions take a `AWSConfig` dictionary as the first argument.
28
- This dictionary holds [`AWSCredentials`](@ref) and AWS region configuration.
70
+ mutable struct AWSCredentials
71
+ access_key_id:: String
72
+ secret_key:: String
73
+ token:: String
74
+ user_arn:: String
75
+ account_number:: String
76
+
77
+ function AWSCredentials (access_key_id, secret_key,
78
+ token= " " , user_arn= " " , account_number= " " )
79
+ new (access_key_id, secret_key, token, user_arn, account_number)
80
+ end
81
+ end
82
+
83
+ """
84
+ AWSConfig
85
+
86
+ Most `AWSCore` functions take an `AWSConfig` object as the first argument.
87
+ This type holds [`AWSCredentials`](@ref), region, and output configuration.
88
+
89
+ # Constructors
90
+
91
+ AWSConfig(; profile, creds, region, output)
29
92
30
- ```julia
31
- aws = AWSConfig(:creds => AWSCredentials(), :region => "us-east-1")`
93
+ Construct an `AWSConfig` object with the given profile, credentials, region, and output
94
+ format. All keyword arguments have default values and are thus optional.
95
+
96
+ * `profile`: Profile name passed to [`AWSCredentials`](@ref), or `nothing` (default)
97
+ * `creds`: `AWSCredentials` object, constructed using `profile` if not provided
98
+ * `region`: Region, read from `AWS_DEFAULT_REGION` if present, otherwise `"us-east-1"`
99
+ * `output`: Output format, defaulting to JSON (`"json"`)
100
+
101
+ # Examples
102
+
103
+ ```julia-repl
104
+ julia> AWSConfig(profile="example", region="ap-southeast-2")
105
+ AWSConfig((AKIDEXAMPLE, wJa...)
106
+ , "ap-southeast-2", "json")
107
+
108
+ julia> AWSConfig(creds=AWSCredentials("AKIDEXAMPLE", "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"))
109
+ AWSConfig((AKIDEXAMPLE, wJa...)
110
+ , "us-east-1", "json")
32
111
```
33
112
"""
34
- const AWSConfig = SymbolDict
113
+ mutable struct AWSConfig
114
+ creds:: AWSCredentials
115
+ region:: String
116
+ output:: String
117
+ end
118
+
119
+ function AWSConfig (; profile= nothing ,
120
+ creds= AWSCredentials (profile= profile),
121
+ region= get (ENV , " AWS_DEFAULT_REGION" , " us-east-1" ),
122
+ output= " json" )
123
+ AWSConfig (creds, region, output)
124
+ end
35
125
126
+ # Relics of using SymbolDict
127
+ import Base: getindex, setindex!
128
+ Base. @deprecate AWSConfig (pairs:: Pair... ) AWSConfig (; pairs... )
129
+ Base. @deprecate getindex (conf:: AWSConfig , x:: Symbol ) getfield (conf, x)
130
+ Base. @deprecate setindex! (conf:: AWSConfig , val, var:: Symbol ) setfield! (conf, var, val)
131
+ Base. @deprecate aws_config AWSConfig
132
+ function Base. get (conf:: AWSConfig , field:: Symbol , alternative)
133
+ Base. depwarn (" get(::AWSConf, a, b) is deprecated; access fields directly instead" , :get )
134
+ if Base. fieldindex (AWSConfig, field, false ) > 0
135
+ getfield (conf, field)
136
+ else
137
+ alternative
138
+ end
139
+ end
140
+ function Base. merge (conf:: AWSConfig , d:: AbstractDict{Symbol,<:Any} )
141
+ Base. depwarn (" merge(::AWSConf, dict) is deprecated; set fields directly instead" , :merge )
142
+ for (k, v) in d
143
+ setfield! (conf, k, v)
144
+ end
145
+ conf
146
+ end
147
+ function Base. merge (d:: AbstractDict{K,V} , conf:: AWSConfig ) where {K,V}
148
+ for f in fieldnames (AWSConfig)
149
+ d[convert (K, f)] = getfield (conf, f)
150
+ end
151
+ d
152
+ end
36
153
37
154
"""
38
155
The `AWSRequest` dictionary describes a single API request:
@@ -57,78 +174,24 @@ include("names.jl")
57
174
include (" mime.jl" )
58
175
59
176
60
-
61
177
# ------------------------------------------------------------------------------#
62
178
# Configuration.
63
179
# ------------------------------------------------------------------------------#
64
180
65
- """
66
- The `aws_config` function provides a simple way to creates an
67
- [`AWSConfig`](@ref) configuration dictionary.
68
-
69
- ```julia
70
- >aws = aws_config()
71
- >aws = aws_config(creds = my_credentials)
72
- >aws = aws_config(region = "ap-southeast-2")
73
- >aws = aws_config(profile = "profile-name")
74
- ```
75
-
76
- By default, the `aws_config` attempts to load AWS credentials from:
77
-
78
- - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` [environemnt variables](http://docs.aws.amazon.com/cli/latest/userguide/cli-environment.html),
79
- - [`~/.aws/credentials`](http://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html) or
80
- - [EC2 Instance Credentials](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#instance-metadata-security-credentials).
81
-
82
- A `~/.aws/credentials` file can be created using the
83
- [AWS CLI](https://aws.amazon.com/cli/) command `aws configrue`.
84
- Or it can be created manually:
85
-
86
- ```ini
87
- [default]
88
- aws_access_key_id = AKIAXXXXXXXXXXXXXXXX
89
- aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
90
- ```
91
-
92
- If your `~/.aws/credentials` file contains multiple profiles you can pass the
93
- profile name as a string to the `profile` keyword argument (`nothing` by
94
- default) or select a profile by setting the `AWS_PROFILE` environment variable.
95
-
96
- `aws_config` understands the following [AWS CLI environment
97
- variables](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-environment):
98
- `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`,
99
- `AWS_DEFAULT_REGION`, `AWS_PROFILE` and `AWS_CONFIG_FILE`.
100
-
101
-
102
- An configuration dictionary can also be created directly from a key pair
103
- as follows. However, putting access credentials in source code is discouraged.
104
-
105
- ```julia
106
- aws = aws_config(creds = AWSCredentials("AKIAXXXXXXXXXXXXXXXX",
107
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"))
108
- ```
181
+ global _default_aws_config = Ref {Union{AWSConfig,Nothing}} (nothing )
109
182
110
183
"""
111
- function aws_config (;profile= nothing ,
112
- creds= AWSCredentials (profile= profile),
113
- region= get (ENV , " AWS_DEFAULT_REGION" , " us-east-1" ),
114
- args... )
115
- @SymDict (creds, region, args... )
116
- end
184
+ default_aws_config()
117
185
118
-
119
- global _default_aws_config = nothing # Union{AWSConfig,Nothing}
120
-
121
-
122
- """
123
- `default_aws_config` returns a global shared [`AWSConfig`](@ref) object
124
- obtained by calling [`aws_config`](@ref) with no optional arguments.
186
+ Return the global shared [`AWSConfig`](@ref) object obtained by calling
187
+ [`AWSConfig()`](@ref) with no arguments.
125
188
"""
126
189
function default_aws_config ()
127
190
global _default_aws_config
128
- if _default_aws_config === nothing
129
- _default_aws_config = aws_config ()
191
+ if _default_aws_config[] === nothing
192
+ _default_aws_config[] = AWSConfig ()
130
193
end
131
- return _default_aws_config
194
+ return _default_aws_config[]
132
195
end
133
196
134
197
@@ -201,7 +264,7 @@ Service endpoint URL for `request`.
201
264
"""
202
265
function service_url (aws, request)
203
266
endpoint = get (request, :endpoint , request[:service ])
204
- region = " ." * aws[ : region]
267
+ region = " ." * aws. region
205
268
if endpoint == " iam" || (endpoint == " sdb" && region == " .us-east-1" )
206
269
region = " "
207
270
end
@@ -220,7 +283,7 @@ function service_query(aws::AWSConfig; args...)
220
283
request = Dict {Symbol,Any} (args)
221
284
222
285
request[:verb ] = " POST"
223
- request[:resource ] = get (aws, :resource , " /" )
286
+ request[:resource ] = " / " # get(aws, :resource, "/") XXX how could config ever have that
224
287
request[:url ] = service_url (aws, request)
225
288
request[:headers ] = Dict (" Content-Type" =>
226
289
" application/x-www-form-urlencoded; charset=utf-8" )
@@ -230,7 +293,7 @@ function service_query(aws::AWSConfig; args...)
230
293
request[:query ][" Version" ] = request[:version ]
231
294
232
295
if request[:service ] == " iam"
233
- aws = merge (aws, Dict ( : region => " us-east-1" ))
296
+ aws. region = " us-east-1"
234
297
end
235
298
if request[:service ] in [" iam" , " sts" , " sqs" , " sns" ]
236
299
request[:query ][" ContentType" ] = " JSON"
0 commit comments