@@ -22,17 +22,134 @@ using DataStructures: OrderedDict
2222using JSON
2323using LazyJSON
2424
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.
2545
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.
2669"""
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)
2992
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")
32111```
33112"""
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
35125
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
36153
37154"""
38155The `AWSRequest` dictionary describes a single API request:
@@ -57,78 +174,24 @@ include("names.jl")
57174include (" mime.jl" )
58175
59176
60-
61177# ------------------------------------------------------------------------------#
62178# Configuration.
63179# ------------------------------------------------------------------------------#
64180
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 )
109182
110183"""
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()
117185
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.
125188"""
126189function default_aws_config ()
127190 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 ()
130193 end
131- return _default_aws_config
194+ return _default_aws_config[]
132195end
133196
134197
@@ -201,7 +264,7 @@ Service endpoint URL for `request`.
201264"""
202265function service_url (aws, request)
203266 endpoint = get (request, :endpoint , request[:service ])
204- region = " ." * aws[ : region]
267+ region = " ." * aws. region
205268 if endpoint == " iam" || (endpoint == " sdb" && region == " .us-east-1" )
206269 region = " "
207270 end
@@ -220,7 +283,7 @@ function service_query(aws::AWSConfig; args...)
220283 request = Dict {Symbol,Any} (args)
221284
222285 request[:verb ] = " POST"
223- request[:resource ] = get (aws, :resource , " /" )
286+ request[:resource ] = " / " # get(aws, :resource, "/") XXX how could config ever have that
224287 request[:url ] = service_url (aws, request)
225288 request[:headers ] = Dict (" Content-Type" =>
226289 " application/x-www-form-urlencoded; charset=utf-8" )
@@ -230,7 +293,7 @@ function service_query(aws::AWSConfig; args...)
230293 request[:query ][" Version" ] = request[:version ]
231294
232295 if request[:service ] == " iam"
233- aws = merge (aws, Dict ( : region => " us-east-1" ))
296+ aws. region = " us-east-1"
234297 end
235298 if request[:service ] in [" iam" , " sts" , " sqs" , " sns" ]
236299 request[:query ][" ContentType" ] = " JSON"
0 commit comments