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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
use crate::credentials_provider::CredentialsProvider;
use url::Url;
/// The configuration settings that control the behavior of archive creation and extraction.
///
///
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
pub struct Config {
/// Override the AWS config and use this region explicitly.
///
/// Users should avoid this option and instead use the official AWS configuration, either in
/// the form of a config file generated by the AWS CLI or the `AWS_REGION` environment
/// variable. This option is provided only for the limited scenarios where alternative
/// configuration options are not suitable.
#[cfg_attr(feature = "clap", clap(long, global = true, value_name = "REGION"))]
pub aws_region: Option<String>,
/// Override the AWS config and use this AWS access key explicitly.
///
/// Users should avoid this option and instead use the official AWS configuration, either in
/// the form of a config file generated by the AWS CLI, env vars, or the EC2 IMDS. This option
/// is provided only for the limited scenarios where alternative configuration options are not
/// suitable, and is not secure enough to use in production.
#[cfg_attr(
feature = "clap",
clap(long, global = true, requires = "aws_secret_access_key")
)]
pub aws_access_key_id: Option<String>,
/// Override the AWS config and use this AWS secret access key explicitly.
///
/// Users should avoid this option and instead use the official AWS configuration, either in
/// the form of a config file generated by the AWS CLI, env vars, or the EC2 IMDS. This option
/// is provided only for the limited scenarios where alternative configuration options are not
/// suitable, and is not secure enough to use in production.
#[cfg_attr(
feature = "clap",
clap(long, global = true, requires = "aws_access_key_id")
)]
pub aws_secret_access_key: Option<String>,
/// Sets AWS session token for AWS operations
///
/// This is required if you use temporal credentials
#[cfg_attr(
feature = "clap",
clap(long, global = true, requires = "aws_secret_access_key")
)]
pub aws_session_token: Option<String>,
/// Uses the provided role-arn, assumes the role and gets the temporary credentials.
///
/// Uses the default environment credentials to assume the role.
///
/// The credentials are automatically refreshed after the `aws_role_session_duration_seconds`, if
/// the `aws_role_session_duration_seconds` is `None` the default duration is 15 minutes
#[cfg_attr(
feature = "clap",
clap(long, global = true, requires = "aws_role_session_name", conflicts_with_all = &["aws_access_key_id", "aws_secret_access_key", "aws_session_token"])
)]
pub aws_role_arn: Option<String>,
/// The session name which will be associated with the temporary credentials of the role which is
/// specified with `--aws-role-arn`
#[cfg_attr(
feature = "clap",
clap(long, global = true, conflicts_with_all = &["aws_access_key_id", "aws_secret_access_key", "aws_session_token"])
)]
pub aws_role_session_name: Option<String>,
/// Overrides the default session duration which is 15 minutes. After this duration the temporary
/// credentials are automatically refreshed
#[cfg_attr(
feature = "clap",
clap(long, global = true, conflicts_with_all = &["aws_access_key_id", "aws_secret_access_key", "aws_session_token"])
)]
pub aws_role_session_duration_seconds: Option<u64>,
/// Custom credentials provider, this is useful if you prefer providing credentials on yourself
/// which may expire from time to time.
#[cfg_attr(feature = "clap", clap(skip))]
pub credentials_provider: Option<CredentialsProvider>,
/// Use a custom S3 endpoint instead of AWS.
///
/// Use this to operate on a non-Amazon S3-compatible service. If this is set, the AWS region
/// is ignored.
#[cfg_attr(feature = "clap", clap(long, global = true, value_name = "URL"))]
pub s3_endpoint: Option<Url>,
/// The chunk size that ssstar uses for multipart transfers of individual files.
///
/// Multipart transfers will be used for objects larger than `multipart_threshold`.
///
/// Can be specified as an integer, ie "1000000", or with a suffix ie "10MB".
///
/// Note that the maximum number of chunks in an upload is 10,000, so for very large objects
/// this chunk size may be overridden if it's smaller than 1/10,000th of the size of the
/// object.
#[cfg_attr(feature = "clap", clap(long, default_value = "8MiB", global = true))]
pub multipart_chunk_size: byte_unit::Byte,
/// The size threshold ssstar uses for multipart transfers of individual objects.
///
/// If an object is this size of larger, then it will be transfered in chunks of
/// `multipart_chunk_size` bytes each.
///
/// Can be specified as an integer, ie "1000000", or with a suffix ie "10MB"
#[cfg_attr(feature = "clap", clap(long, default_value = "8MiB", global = true))]
pub multipart_threshold: byte_unit::Byte,
/// The maximum number of concurrent requests to the bucket when performing transfers.
///
/// In case of multipart transfers, each chunk counts as a separate request.
///
/// A higher number of concurrent requests may be necessary in order to saturate very fast
/// connections to S3, but this will also increase RAM usage during the transfer.
#[cfg_attr(feature = "clap", clap(long, default_value = "10", global = true))]
pub max_concurrent_requests: usize,
/// The maximum number of tasks in the task queue.
///
/// In case of multipart transfers, each chunk counts as a separate task.
#[cfg_attr(feature = "clap", clap(long, default_value = "1000", global = true))]
pub max_queue_size: usize,
/// The user agent to send to the S3 API endpoint.
///
/// This defaults to something provided by the AWS SDK for Rust.
#[cfg_attr(feature = "clap", clap(long, global = true))]
pub user_agent: Option<String>,
}
impl Default for Config {
fn default() -> Self {
// XXX: Unfortunately this is duplicated here and in the `clap` attributes, unfortunately I
// can't find a better way unless we unconditionally take a clap dependency in the lib
// crate which I'm not willing to do
Self {
aws_region: None,
aws_access_key_id: None,
aws_secret_access_key: None,
aws_session_token: None,
aws_role_arn: None,
aws_role_session_name: None,
aws_role_session_duration_seconds: None,
credentials_provider: None,
s3_endpoint: None,
multipart_chunk_size: byte_unit::Byte::from_bytes(8 * 1024 * 1024),
multipart_threshold: byte_unit::Byte::from_bytes(8 * 1024 * 1024),
max_concurrent_requests: 10,
max_queue_size: 1000,
user_agent: None,
}
}
}
#[cfg(feature = "clap")]
#[cfg(test)]
mod tests {
use super::*;
/// If clap is enabled, verify that the `Default` impl and the clap-declared defaults match, to
/// detect if they ever drift out of sync in the future
#[test]
fn defaults_match() {
use clap::Parser;
let args: &'static [&'static str] = &[];
let clap_default = Config::parse_from(args);
let rust_default = Config::default();
assert_eq!(clap_default, rust_default);
}
}