fog-aws 3.6.7 → 3.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b18145d8a9c814854524a02640ca995f074ae8a63c232ab50a6fc84f7387237c
4
- data.tar.gz: 36346830f2b660a561b372b9fd8b7c48d58f95bb53971d480199477909d4fe9b
3
+ metadata.gz: 9ac0628bad4edf849a2b1395bd829d18ae77bff352841e68fbc7ecdb475ef82b
4
+ data.tar.gz: 5a545b7e8ad44c321273fac7b87b11b79be3a9af1c2d038b2790ea95c529df30
5
5
  SHA512:
6
- metadata.gz: 29957fd751f2ee82a52cf0bbbff5740a5e80e6e3c6a9cd9aa5da486b4cd1c2fbe1a19486a2ecddfd92731183e4650ca839886ce2ba7d6a5ff991db6d814fbd3e
7
- data.tar.gz: f869e131ec87666ad2e0741e858d2f107613fc7e1151683e32dc650e844420ec0692beaae74eeb018e3297d346c14cbe59a76af7c1d754c62fc9052426e80bfb
6
+ metadata.gz: 06156a44eec55618672a3d5beed5d35c0e7195ba07a3a515e944db462edbd6b4e56f6ff693bd5dd0013090c2083f395cf9f310013a164d3a3163c7ea82f96b9e
7
+ data.tar.gz: ebf606599061ed26cf2f1995e91690aebb7b409b15fe1d6ee465ef3e36a87b9c714e376e9bf6fee9c276a45a994972d94a24ef49d27f92e8b64ee6a47a9ae082
@@ -19,6 +19,14 @@ matrix:
19
19
  gemfile: Gemfile
20
20
  - rvm: 2.5.0
21
21
  gemfile: gemfiles/Gemfile-edge
22
+ - rvm: 2.6.6
23
+ gemfile: Gemfile
24
+ - rvm: 2.6.6
25
+ gemfile: gemfiles/Gemfile-edge
26
+ - rvm: 2.7.2
27
+ gemfile: Gemfile
28
+ - rvm: 2.7.2
29
+ gemfile: gemfiles/Gemfile-edge
22
30
  - rvm: jruby-head
23
31
  gemfile: Gemfile
24
32
  allow_failures:
@@ -32,6 +40,10 @@ matrix:
32
40
  gemfile: gemfiles/Gemfile-edge
33
41
  - rvm: 2.5.0
34
42
  gemfile: gemfiles/Gemfile-edge
43
+ - rvm: 2.6.6
44
+ gemfile: gemfiles/Gemfile-edge
45
+ - rvm: 2.7.2
46
+ gemfile: gemfiles/Gemfile-edge
35
47
  notifications:
36
48
  email: false
37
49
  irc:
@@ -1,8 +1,23 @@
1
1
  # Change Log
2
2
 
3
- ## [v3.6.7](https://github.com/fog/fog-aws/tree/HEAD)(2020-08-26)
3
+ ## [v3.7.0](https://github.com/fog/fog-aws/tree/v3.7.0) (2020-12-01)
4
+ [Full Changelog](https://github.com/fog/fog-aws/compare/v3.7.0...HEAD)
4
5
 
5
- [Full Changelog](https://github.com/fog/fog-aws/compare/v3.6.6...HEAD)
6
+ **Closed issues:**
7
+
8
+ - File\#copy does not support files above 5 GB [\#577](https://github.com/fog/fog-aws/issues/577)
9
+ - fog-aws: AWS extended length resource ID issues \(8-\>18\) [\#517](https://github.com/fog/fog-aws/issues/517)
10
+
11
+ **Merged pull requests:**
12
+
13
+ - Add all m6gd, r6g, r6gd, c6g, and c6gd instance classes [\#582](https://github.com/fog/fog-aws/pull/582) ([calebwoofenden](https://github.com/calebwoofenden))
14
+ - Test Ruby v2.6.6 and v2.7.2 in CI [\#581](https://github.com/fog/fog-aws/pull/581) ([stanhu](https://github.com/stanhu))
15
+ - Add multi-threaded support for File\#copy [\#579](https://github.com/fog/fog-aws/pull/579) ([stanhu](https://github.com/stanhu))
16
+ - Add support for multipart Fog::AWS::Storage::File\#copy [\#578](https://github.com/fog/fog-aws/pull/578) ([stanhu](https://github.com/stanhu))
17
+ - Add AssumeRoleWithWebIdentity to fetch\_credentials [\#576](https://github.com/fog/fog-aws/pull/576) ([jpac-run](https://github.com/jpac-run))
18
+
19
+ ## [v3.6.7](https://github.com/fog/fog-aws/tree/v3.6.7) (2020-08-26)
20
+ [Full Changelog](https://github.com/fog/fog-aws/compare/v3.6.6...v3.6.7)
6
21
 
7
22
  **Merged pull requests:**
8
23
 
@@ -293,6 +308,7 @@
293
308
 
294
309
  - Update changelog for 1.4.0 [\#383](https://github.com/fog/fog-aws/pull/383) ([greysteil](https://github.com/greysteil))
295
310
  - Allow specifying kms key id to use [\#382](https://github.com/fog/fog-aws/pull/382) ([fcheung](https://github.com/fcheung))
311
+ - added support to retrieve and create vpc with ipv6 cidr block [\#381](https://github.com/fog/fog-aws/pull/381) ([chanakyacool](https://github.com/chanakyacool))
296
312
  - Add MaxResults filter to describe reserved instances offerings [\#376](https://github.com/fog/fog-aws/pull/376) ([KevinLoiseau](https://github.com/KevinLoiseau))
297
313
  - Fix Fog::Compute::AWS::Images\#all [\#375](https://github.com/fog/fog-aws/pull/375) ([eddiej](https://github.com/eddiej))
298
314
  - Fix AWS credential mocking [\#374](https://github.com/fog/fog-aws/pull/374) ([v-yarotsky](https://github.com/v-yarotsky))
@@ -310,7 +326,6 @@
310
326
 
311
327
  **Merged pull requests:**
312
328
 
313
- - added support to retrieve and create vpc with ipv6 cidr block [\#381](https://github.com/fog/fog-aws/pull/381) ([chanakyacool](https://github.com/chanakyacool))
314
329
  - add NextContinuationToken support to GetBucket operation [\#370](https://github.com/fog/fog-aws/pull/370) ([khoan](https://github.com/khoan))
315
330
  - Add a top-level require that matches the gem name [\#367](https://github.com/fog/fog-aws/pull/367) ([lanej](https://github.com/lanej))
316
331
  - Fixed credential refresh when instance metadata host is inaccessible [\#366](https://github.com/fog/fog-aws/pull/366) ([ankane](https://github.com/ankane))
data/Gemfile CHANGED
@@ -11,4 +11,4 @@ end
11
11
  group :test do
12
12
  gem "simplecov"
13
13
  gem "codeclimate-test-reporter", "~> 1.0.0"
14
- end
14
+ end
data/README.md CHANGED
@@ -105,6 +105,26 @@ directory.files
105
105
  directory.files.new(key: 'user/1/Gemfile').url(Time.now + 60)
106
106
  ```
107
107
 
108
+ #### Copying a file
109
+
110
+ ```ruby
111
+ directory = s3.directories.new(key: 'gaudi-portal-dev')
112
+ file = directory.files.get('user/1/Gemfile')
113
+ file.copy("target-bucket", "user/2/Gemfile.copy")
114
+ ```
115
+
116
+ To speed transfers of large files, the `concurrency` option can be used
117
+ to spawn multiple threads. Note that the file must be at least 5 MB for
118
+ multipart uploads to work. For example:
119
+
120
+ ```ruby
121
+ directory = s3.directories.new(key: 'gaudi-portal-dev')
122
+ file = directory.files.get('user/1/Gemfile')
123
+ file.multipart_chunk_size = 10 * 1024 * 1024
124
+ file.concurrency = 10
125
+ file.copy("target-bucket", "user/2/Gemfile.copy")
126
+ ```
127
+
108
128
  ## Documentation
109
129
 
110
130
  See the [online documentation](http://www.rubydoc.info/github/fog/fog-aws) for a complete API reference.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Fog
2
4
  module AWS
3
5
  module CredentialFetcher
@@ -9,6 +11,8 @@ module Fog
9
11
 
10
12
  CONTAINER_CREDENTIALS_HOST = "http://169.254.170.2"
11
13
 
14
+ STS_GLOBAL_ENDPOINT = "https://sts.amazonaws.com"
15
+
12
16
  module ServiceMethods
13
17
  def fetch_credentials(options)
14
18
  if options[:use_iam_profile] && Fog.mocking?
@@ -23,6 +27,30 @@ module Fog
23
27
  connection = options[:connection] || Excon.new(CONTAINER_CREDENTIALS_HOST)
24
28
  credential_path = options[:credential_path] || ENV["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"]
25
29
  role_data = connection.get(:path => credential_path, :idempotent => true, :expects => 200).body
30
+ session = Fog::JSON.decode(role_data)
31
+
32
+ if region.nil?
33
+ connection = options[:metadata_connection] || Excon.new(INSTANCE_METADATA_HOST)
34
+ token_header = fetch_credentials_token_header(connection, options[:disable_imds_v2])
35
+ region = connection.get(:path => INSTANCE_METADATA_AZ, :idempotent => true, :expects => 200, :headers => token_header).body[0..-2]
36
+ end
37
+ elsif ENV["AWS_WEB_IDENTITY_TOKEN_FILE"]
38
+ params = {
39
+ :Action => "AssumeRoleWithWebIdentity",
40
+ :RoleArn => options[:role_arn] || ENV.fetch("AWS_ROLE_ARN"),
41
+ :RoleSessionName => options[:role_session_name] || ENV.fetch("AWS_ROLE_SESSION_NAME"),
42
+ :WebIdentityToken => File.read(options[:aws_web_identity_token_file] || ENV.fetch("AWS_WEB_IDENTITY_TOKEN_FILE")),
43
+ :Version => "2011-06-15",
44
+ }
45
+ connection = options[:connection] || Excon.new(STS_GLOBAL_ENDPOINT, :query => params)
46
+ document = Nokogiri::XML(connection.get(:idempotent => true, :expects => 200).body)
47
+
48
+ session = {
49
+ "AccessKeyId" => document.css("AccessKeyId").children.text,
50
+ "SecretAccessKey" => document.css("SecretAccessKey").children.text,
51
+ "Token" => document.css("SessionToken").children.text,
52
+ "Expiration" => document.css("Expiration").children.text,
53
+ }
26
54
 
27
55
  if region.nil?
28
56
  connection = options[:metadata_connection] || Excon.new(INSTANCE_METADATA_HOST)
@@ -34,16 +62,17 @@ module Fog
34
62
  token_header = fetch_credentials_token_header(connection, options[:disable_imds_v2])
35
63
  role_name = connection.get(:path => INSTANCE_METADATA_PATH, :idempotent => true, :expects => 200, :headers => token_header).body
36
64
  role_data = connection.get(:path => INSTANCE_METADATA_PATH+role_name, :idempotent => true, :expects => 200, :headers => token_header).body
65
+ session = Fog::JSON.decode(role_data)
66
+
37
67
  region ||= connection.get(:path => INSTANCE_METADATA_AZ, :idempotent => true, :expects => 200, :headers => token_header).body[0..-2]
38
68
  end
39
-
40
- session = Fog::JSON.decode(role_data)
69
+
41
70
  credentials = {}
42
71
  credentials[:aws_access_key_id] = session['AccessKeyId']
43
72
  credentials[:aws_secret_access_key] = session['SecretAccessKey']
44
73
  credentials[:aws_session_token] = session['Token']
45
74
  credentials[:aws_credentials_expire_at] = Time.xmlschema session['Expiration']
46
-
75
+
47
76
  # set region by default to the one the instance is in.
48
77
  credentials[:region] = region
49
78
  #these indicate the metadata service is unavailable or has no profile setup
@@ -366,6 +366,106 @@ module Fog
366
366
  :ebs_optimized_available => true,
367
367
  :instance_store_volumes => 0
368
368
  },
369
+ {
370
+ :id => 'm6g.metal',
371
+ :name => 'M6G Metal',
372
+ :bits => 64,
373
+ :cores => 64,
374
+ :disk => 0,
375
+ :ram => 274878,
376
+ :ebs_optimized_available => true,
377
+ :instance_store_volumes => 0
378
+ },
379
+ {
380
+ :id => 'm6gd.medium',
381
+ :name => 'M6GD Medium',
382
+ :bits => 64,
383
+ :cores => 1,
384
+ :disk => 59,
385
+ :ram => 4295,
386
+ :ebs_optimized_available => true,
387
+ :instance_store_volumes => 1
388
+ },
389
+ {
390
+ :id => 'm6gd.large',
391
+ :name => 'M6GD Large',
392
+ :bits => 64,
393
+ :cores => 2,
394
+ :disk => 118,
395
+ :ram => 8590,
396
+ :ebs_optimized_available => true,
397
+ :instance_store_volumes => 1
398
+ },
399
+ {
400
+ :id => 'm6gd.xlarge',
401
+ :name => 'M6GD Extra Large',
402
+ :bits => 64,
403
+ :cores => 4,
404
+ :disk => 237,
405
+ :ram => 17180,
406
+ :ebs_optimized_available => true,
407
+ :instance_store_volumes => 1
408
+ },
409
+ {
410
+ :id => 'm6gd.2xlarge',
411
+ :name => 'M6GD Double Extra Large',
412
+ :bits => 64,
413
+ :cores => 8,
414
+ :disk => 474,
415
+ :ram => 34360,
416
+ :ebs_optimized_available => true,
417
+ :instance_store_volumes => 1
418
+ },
419
+ {
420
+ :id => 'm6gd.4xlarge',
421
+ :name => 'M6GD Quadruple Extra Large',
422
+ :bits => 64,
423
+ :cores => 16,
424
+ :disk => 950,
425
+ :ram => 68719,
426
+ :ebs_optimized_available => true,
427
+ :instance_store_volumes => 1
428
+ },
429
+ {
430
+ :id => 'm6gd.8xlarge',
431
+ :name => 'M6GD Octuple Extra Large',
432
+ :bits => 64,
433
+ :cores => 32,
434
+ :disk => 1900,
435
+ :ram => 137439,
436
+ :ebs_optimized_available => true,
437
+ :instance_store_volumes => 1
438
+ },
439
+ {
440
+ :id => 'm6gd.12xlarge',
441
+ :name => 'M6GD Twelve Extra Large',
442
+ :bits => 64,
443
+ :cores => 48,
444
+ :disk => 2850,
445
+ :ram => 206158,
446
+ :ebs_optimized_available => true,
447
+ :instance_store_volumes => 2
448
+ },
449
+ {
450
+ :id => 'm6gd.16xlarge',
451
+ :name => 'M6GD Sixteen Extra Large',
452
+ :bits => 64,
453
+ :cores => 64,
454
+ :disk => 3800,
455
+ :ram => 274878,
456
+ :ebs_optimized_available => true,
457
+ :instance_store_volumes => 2
458
+ },
459
+ {
460
+ :id => 'm6gd.metal',
461
+ :name => 'M6GD Metal',
462
+ :bits => 64,
463
+ :cores => 64,
464
+ :disk => 3800,
465
+ :ram => 274878,
466
+ :ebs_optimized_available => true,
467
+ :instance_store_volumes => 2
468
+ },
369
469
  {
370
470
  :id => 'm1.small',
371
471
  :name => 'M1 Small Instance',
@@ -776,6 +876,186 @@ module Fog
776
876
  :ebs_optimized_available => true,
777
877
  :instance_store_volumes => 0
778
878
  },
879
+ {
880
+ :id => 'c6g.medium',
881
+ :name => 'C6G Medium',
882
+ :bits => 64,
883
+ :cores => 1,
884
+ :disk => 0,
885
+ :ram => 2147,
886
+ :ebs_optimized_available => true,
887
+ :instance_store_volumes => 0
888
+ },
889
+ {
890
+ :id => 'c6g.large',
891
+ :name => 'C6G Large',
892
+ :bits => 64,
893
+ :cores => 2,
894
+ :disk => 0,
895
+ :ram => 4295,
896
+ :ebs_optimized_available => true,
897
+ :instance_store_volumes => 0
898
+ },
899
+ {
900
+ :id => 'c6g.xlarge',
901
+ :name => 'C6G Extra Large',
902
+ :bits => 64,
903
+ :cores => 4,
904
+ :disk => 0,
905
+ :ram => 8590,
906
+ :ebs_optimized_available => true,
907
+ :instance_store_volumes => 0
908
+ },
909
+ {
910
+ :id => 'c6g.2xlarge',
911
+ :name => 'C6G Double Extra Large',
912
+ :bits => 64,
913
+ :cores => 8,
914
+ :disk => 0,
915
+ :ram => 17180,
916
+ :ebs_optimized_available => true,
917
+ :instance_store_volumes => 0
918
+ },
919
+ {
920
+ :id => 'c6g.4xlarge',
921
+ :name => 'C6G Quadruple Extra Large',
922
+ :bits => 64,
923
+ :cores => 16,
924
+ :disk => 0,
925
+ :ram => 34360,
926
+ :ebs_optimized_available => true,
927
+ :instance_store_volumes => 0
928
+ },
929
+ {
930
+ :id => 'c6g.8xlarge',
931
+ :name => 'C6G Octuple Extra Large',
932
+ :bits => 64,
933
+ :cores => 32,
934
+ :disk => 0,
935
+ :ram => 68719,
936
+ :ebs_optimized_available => true,
937
+ :instance_store_volumes => 0
938
+ },
939
+ {
940
+ :id => 'c6g.12xlarge',
941
+ :name => 'C6G Twelve Extra Large',
942
+ :bits => 64,
943
+ :cores => 48,
944
+ :disk => 0,
945
+ :ram => 103079,
946
+ :ebs_optimized_available => true,
947
+ :instance_store_volumes => 0
948
+ },
949
+ {
950
+ :id => 'c6g.16xlarge',
951
+ :name => 'C6G Sixteen Extra Large',
952
+ :bits => 64,
953
+ :cores => 64,
954
+ :disk => 0,
955
+ :ram => 137439,
956
+ :ebs_optimized_available => true,
957
+ :instance_store_volumes => 0
958
+ },
959
+ {
960
+ :id => 'c6g.metal',
961
+ :name => 'C6G Metal',
962
+ :bits => 64,
963
+ :cores => 64,
964
+ :disk => 0,
965
+ :ram => 137439,
966
+ :ebs_optimized_available => true,
967
+ :instance_store_volumes => 0
968
+ },
969
+ {
970
+ :id => 'c6gd.medium',
971
+ :name => 'C6GD Medium',
972
+ :bits => 64,
973
+ :cores => 1,
974
+ :disk => 59,
975
+ :ram => 2147,
976
+ :ebs_optimized_available => true,
977
+ :instance_store_volumes => 1
978
+ },
979
+ {
980
+ :id => 'c6gd.large',
981
+ :name => 'C6GD Large',
982
+ :bits => 64,
983
+ :cores => 2,
984
+ :disk => 118,
985
+ :ram => 4295,
986
+ :ebs_optimized_available => true,
987
+ :instance_store_volumes => 1
988
+ },
989
+ {
990
+ :id => 'c6gd.xlarge',
991
+ :name => 'C6GD Extra Large',
992
+ :bits => 64,
993
+ :cores => 4,
994
+ :disk => 237,
995
+ :ram => 8590,
996
+ :ebs_optimized_available => true,
997
+ :instance_store_volumes => 1
998
+ },
999
+ {
1000
+ :id => 'c6gd.2xlarge',
1001
+ :name => 'C6GD Double Extra Large',
1002
+ :bits => 64,
1003
+ :cores => 8,
1004
+ :disk => 474,
1005
+ :ram => 17180,
1006
+ :ebs_optimized_available => true,
1007
+ :instance_store_volumes => 1
1008
+ },
1009
+ {
1010
+ :id => 'c6gd.4xlarge',
1011
+ :name => 'C6GD Quadruple Extra Large',
1012
+ :bits => 64,
1013
+ :cores => 16,
1014
+ :disk => 950,
1015
+ :ram => 34360,
1016
+ :ebs_optimized_available => true,
1017
+ :instance_store_volumes => 1
1018
+ },
1019
+ {
1020
+ :id => 'c6gd.8xlarge',
1021
+ :name => 'C6GD Octuple Extra Large',
1022
+ :bits => 64,
1023
+ :cores => 32,
1024
+ :disk => 1900,
1025
+ :ram => 68719,
1026
+ :ebs_optimized_available => true,
1027
+ :instance_store_volumes => 1
1028
+ },
1029
+ {
1030
+ :id => 'c6gd.12xlarge',
1031
+ :name => 'C6GD Twelve Extra Large',
1032
+ :bits => 64,
1033
+ :cores => 48,
1034
+ :disk => 2850,
1035
+ :ram => 103079,
1036
+ :ebs_optimized_available => true,
1037
+ :instance_store_volumes => 2
1038
+ },
1039
+ {
1040
+ :id => 'c6gd.16xlarge',
1041
+ :name => 'C6GD Sixteen Extra Large',
1042
+ :bits => 64,
1043
+ :cores => 64,
1044
+ :disk => 3800,
1045
+ :ram => 137439,
1046
+ :ebs_optimized_available => true,
1047
+ :instance_store_volumes => 2
1048
+ },
1049
+ {
1050
+ :id => 'c6gd.metal',
1051
+ :name => 'C6GD Metal',
1052
+ :bits => 64,
1053
+ :cores => 64,
1054
+ :disk => 3800,
1055
+ :ram => 137439,
1056
+ :ebs_optimized_available => true,
1057
+ :instance_store_volumes => 2
1058
+ },
779
1059
  {
780
1060
  :id => 'g2.2xlarge',
781
1061
  :name => 'GPU Double Extra Large',
@@ -1696,6 +1976,186 @@ module Fog
1696
1976
  :ebs_optimized_available => true,
1697
1977
  :instance_store_volumes => 4
1698
1978
  },
1979
+ {
1980
+ :id => 'r6g.medium',
1981
+ :name => 'R6G Medium',
1982
+ :bits => 64,
1983
+ :cores => 1,
1984
+ :disk => 0,
1985
+ :ram => 8590,
1986
+ :ebs_optimized_available => true,
1987
+ :instance_store_volumes => 0
1988
+ },
1989
+ {
1990
+ :id => 'r6g.large',
1991
+ :name => 'R6G Large',
1992
+ :bits => 64,
1993
+ :cores => 2,
1994
+ :disk => 0,
1995
+ :ram => 17180,
1996
+ :ebs_optimized_available => true,
1997
+ :instance_store_volumes => 0
1998
+ },
1999
+ {
2000
+ :id => 'r6g.xlarge',
2001
+ :name => 'R6G Extra Large',
2002
+ :bits => 64,
2003
+ :cores => 4,
2004
+ :disk => 0,
2005
+ :ram => 34360,
2006
+ :ebs_optimized_available => true,
2007
+ :instance_store_volumes => 0
2008
+ },
2009
+ {
2010
+ :id => 'r6g.2xlarge',
2011
+ :name => 'R6G Double Extra Large',
2012
+ :bits => 64,
2013
+ :cores => 8,
2014
+ :disk => 0,
2015
+ :ram => 68719,
2016
+ :ebs_optimized_available => true,
2017
+ :instance_store_volumes => 0
2018
+ },
2019
+ {
2020
+ :id => 'r6g.4xlarge',
2021
+ :name => 'R6G Quadruple Extra Large',
2022
+ :bits => 64,
2023
+ :cores => 16,
2024
+ :disk => 0,
2025
+ :ram => 137439,
2026
+ :ebs_optimized_available => true,
2027
+ :instance_store_volumes => 0
2028
+ },
2029
+ {
2030
+ :id => 'r6g.8xlarge',
2031
+ :name => 'R6G Octuple Extra Large',
2032
+ :bits => 64,
2033
+ :cores => 32,
2034
+ :disk => 0,
2035
+ :ram => 274878,
2036
+ :ebs_optimized_available => true,
2037
+ :instance_store_volumes => 0
2038
+ },
2039
+ {
2040
+ :id => 'r6g.12xlarge',
2041
+ :name => 'R6G Twelve Extra Large',
2042
+ :bits => 64,
2043
+ :cores => 48,
2044
+ :disk => 0,
2045
+ :ram => 412317,
2046
+ :ebs_optimized_available => true,
2047
+ :instance_store_volumes => 0
2048
+ },
2049
+ {
2050
+ :id => 'r6g.16xlarge',
2051
+ :name => 'R6G Sixteen Extra Large',
2052
+ :bits => 64,
2053
+ :cores => 64,
2054
+ :disk => 0,
2055
+ :ram => 549756,
2056
+ :ebs_optimized_available => true,
2057
+ :instance_store_volumes => 0
2058
+ },
2059
+ {
2060
+ :id => 'r6g.metal',
2061
+ :name => 'R6G Metal',
2062
+ :bits => 64,
2063
+ :cores => 64,
2064
+ :disk => 0,
2065
+ :ram => 549756,
2066
+ :ebs_optimized_available => true,
2067
+ :instance_store_volumes => 0
2068
+ },
2069
+ {
2070
+ :id => 'r6gd.medium',
2071
+ :name => 'R6GD Medium',
2072
+ :bits => 64,
2073
+ :cores => 1,
2074
+ :disk => 59,
2075
+ :ram => 8590,
2076
+ :ebs_optimized_available => true,
2077
+ :instance_store_volumes => 1
2078
+ },
2079
+ {
2080
+ :id => 'r6gd.large',
2081
+ :name => 'R6GD Large',
2082
+ :bits => 64,
2083
+ :cores => 2,
2084
+ :disk => 118,
2085
+ :ram => 17180,
2086
+ :ebs_optimized_available => true,
2087
+ :instance_store_volumes => 1
2088
+ },
2089
+ {
2090
+ :id => 'r6gd.xlarge',
2091
+ :name => 'R6GD Extra Large',
2092
+ :bits => 64,
2093
+ :cores => 4,
2094
+ :disk => 237,
2095
+ :ram => 34360,
2096
+ :ebs_optimized_available => true,
2097
+ :instance_store_volumes => 1
2098
+ },
2099
+ {
2100
+ :id => 'r6gd.2xlarge',
2101
+ :name => 'R6GD Double Extra Large',
2102
+ :bits => 64,
2103
+ :cores => 8,
2104
+ :disk => 474,
2105
+ :ram => 68719,
2106
+ :ebs_optimized_available => true,
2107
+ :instance_store_volumes => 1
2108
+ },
2109
+ {
2110
+ :id => 'r6gd.4xlarge',
2111
+ :name => 'R6GD Quadruple Extra Large',
2112
+ :bits => 64,
2113
+ :cores => 16,
2114
+ :disk => 950,
2115
+ :ram => 137439,
2116
+ :ebs_optimized_available => true,
2117
+ :instance_store_volumes => 1
2118
+ },
2119
+ {
2120
+ :id => 'r6gd.8xlarge',
2121
+ :name => 'R6GD Octuple Extra Large',
2122
+ :bits => 64,
2123
+ :cores => 32,
2124
+ :disk => 1900,
2125
+ :ram => 274878,
2126
+ :ebs_optimized_available => true,
2127
+ :instance_store_volumes => 1
2128
+ },
2129
+ {
2130
+ :id => 'r6gd.12xlarge',
2131
+ :name => 'R6GD Twelve Extra Large',
2132
+ :bits => 64,
2133
+ :cores => 48,
2134
+ :disk => 2850,
2135
+ :ram => 412317,
2136
+ :ebs_optimized_available => true,
2137
+ :instance_store_volumes => 2
2138
+ },
2139
+ {
2140
+ :id => 'r6gd.16xlarge',
2141
+ :name => 'R6GD Sixteen Extra Large',
2142
+ :bits => 64,
2143
+ :cores => 64,
2144
+ :disk => 3800,
2145
+ :ram => 549756,
2146
+ :ebs_optimized_available => true,
2147
+ :instance_store_volumes => 2
2148
+ },
2149
+ {
2150
+ :id => 'r6gd.metal',
2151
+ :name => 'R6GD Metal',
2152
+ :bits => 64,
2153
+ :cores => 64,
2154
+ :disk => 3800,
2155
+ :ram => 549756,
2156
+ :ebs_optimized_available => true,
2157
+ :instance_store_volumes => 2
2158
+ },
1699
2159
  {
1700
2160
  :id => "x1.16xlarge",
1701
2161
  :name => "X1 Sixteen Extra Large",
@@ -4,6 +4,10 @@ module Fog
4
4
  module AWS
5
5
  class Storage
6
6
  class File < Fog::Model
7
+ MIN_MULTIPART_CHUNK_SIZE = 5242880
8
+ MAX_SINGLE_PUT_SIZE = 5368709120
9
+ MULTIPART_COPY_THRESHOLD = 15728640
10
+
7
11
  # @see AWS Object docs http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectOps.html
8
12
 
9
13
  identity :key, :aliases => 'Key'
@@ -27,14 +31,54 @@ module Fog
27
31
  attribute :kms_key_id, :aliases => 'x-amz-server-side-encryption-aws-kms-key-id'
28
32
  attribute :tags, :aliases => 'x-amz-tagging'
29
33
 
34
+ UploadPartData = Struct.new(:part_number, :upload_options, :etag)
35
+
36
+ class PartList
37
+ def initialize(parts = [])
38
+ @parts = parts
39
+ @mutex = Mutex.new
40
+ end
41
+
42
+ def push(part)
43
+ @mutex.synchronize { @parts.push(part) }
44
+ end
45
+
46
+ def shift
47
+ @mutex.synchronize { @parts.shift }
48
+ end
49
+
50
+ def clear!
51
+ @mutex.synchronize { @parts.clear }
52
+ end
53
+
54
+ def size
55
+ @mutex.synchronize { @parts.size }
56
+ end
57
+
58
+ def to_a
59
+ @mutex.synchronize { @parts.dup }
60
+ end
61
+ end
62
+
30
63
  # @note Chunk size to use for multipart uploads.
31
64
  # Use small chunk sizes to minimize memory. E.g. 5242880 = 5mb
32
65
  attr_reader :multipart_chunk_size
33
66
  def multipart_chunk_size=(mp_chunk_size)
34
- raise ArgumentError.new("minimum multipart_chunk_size is 5242880") if mp_chunk_size < 5242880
67
+ raise ArgumentError.new("minimum multipart_chunk_size is #{MIN_MULTIPART_CHUNK_SIZE}") if mp_chunk_size < MIN_MULTIPART_CHUNK_SIZE
35
68
  @multipart_chunk_size = mp_chunk_size
36
69
  end
37
70
 
71
+ # @note Number of threads used to copy files.
72
+ def concurrency=(concurrency)
73
+ raise ArgumentError.new('minimum concurrency is 1') if concurrency.to_i < 1
74
+
75
+ @concurrency = concurrency.to_i
76
+ end
77
+
78
+ def concurrency
79
+ @concurrency || 1
80
+ end
81
+
38
82
  def acl
39
83
  requires :directory, :key
40
84
  service.get_object_acl(directory.key, key).body['AccessControlList']
@@ -99,7 +143,17 @@ module Fog
99
143
  #
100
144
  def copy(target_directory_key, target_file_key, options = {})
101
145
  requires :directory, :key
102
- service.copy_object(directory.key, key, target_directory_key, target_file_key, options)
146
+
147
+ # With a single PUT operation you can upload objects up to 5 GB in size. Automatically set MP for larger objects.
148
+ self.multipart_chunk_size = MIN_MULTIPART_CHUNK_SIZE * 2 if !multipart_chunk_size && self.content_length.to_i > MAX_SINGLE_PUT_SIZE
149
+
150
+ if multipart_chunk_size && self.content_length.to_i >= multipart_chunk_size
151
+ upload_part_options = options.merge({ 'x-amz-copy-source' => "#{directory.key}/#{key}" })
152
+ multipart_copy(options, upload_part_options, target_directory_key, target_file_key)
153
+ else
154
+ service.copy_object(directory.key, key, target_directory_key, target_file_key, options)
155
+ end
156
+
103
157
  target_directory = service.directories.new(:key => target_directory_key)
104
158
  target_directory.files.head(target_file_key)
105
159
  end
@@ -214,7 +268,7 @@ module Fog
214
268
  options.merge!(encryption_headers)
215
269
 
216
270
  # With a single PUT operation you can upload objects up to 5 GB in size. Automatically set MP for larger objects.
217
- self.multipart_chunk_size = 5242880 if !multipart_chunk_size && Fog::Storage.get_body_size(body) > 5368709120
271
+ self.multipart_chunk_size = MIN_MULTIPART_CHUNK_SIZE if !multipart_chunk_size && Fog::Storage.get_body_size(body) > MAX_SINGLE_PUT_SIZE
218
272
 
219
273
  if multipart_chunk_size && Fog::Storage.get_body_size(body) >= multipart_chunk_size && body.respond_to?(:read)
220
274
  data = multipart_save(options)
@@ -294,6 +348,30 @@ module Fog
294
348
  service.complete_multipart_upload(directory.key, key, upload_id, part_tags)
295
349
  end
296
350
 
351
+ def multipart_copy(options, upload_part_options, target_directory_key, target_file_key)
352
+ # Initiate the upload
353
+ res = service.initiate_multipart_upload(target_directory_key, target_file_key, options)
354
+ upload_id = res.body["UploadId"]
355
+
356
+ # Store ETags of upload parts
357
+ part_tags = []
358
+ pending = PartList.new(create_part_list(upload_part_options))
359
+ thread_count = self.concurrency
360
+ completed = PartList.new
361
+ errors = upload_in_threads(target_directory_key, target_file_key, upload_id, pending, completed, thread_count)
362
+
363
+ raise error.first if errors.any?
364
+
365
+ part_tags = completed.to_a.sort_by { |part| part.part_number }.map(&:etag)
366
+ rescue => e
367
+ # Abort the upload & reraise
368
+ service.abort_multipart_upload(target_directory_key, target_file_key, upload_id) if upload_id
369
+ raise
370
+ else
371
+ # Complete the upload
372
+ service.complete_multipart_upload(target_directory_key, target_file_key, upload_id, part_tags)
373
+ end
374
+
297
375
  def encryption_headers
298
376
  if encryption && encryption_key
299
377
  encryption_customer_key_headers
@@ -318,6 +396,49 @@ module Fog
318
396
  'x-amz-server-side-encryption-customer-key-md5' => Base64.encode64(OpenSSL::Digest::MD5.digest(encryption_key.to_s)).chomp!
319
397
  }
320
398
  end
399
+
400
+ def create_part_list(upload_part_options)
401
+ current_pos = 0
402
+ count = 0
403
+ pending = []
404
+
405
+ while current_pos < self.content_length do
406
+ start_pos = current_pos
407
+ end_pos = [current_pos + self.multipart_chunk_size, self.content_length - 1].min
408
+ range = "bytes=#{start_pos}-#{end_pos}"
409
+ part_options = upload_part_options.dup
410
+ part_options['x-amz-copy-source-range'] = range
411
+ pending << UploadPartData.new(count + 1, part_options, nil)
412
+ count += 1
413
+ current_pos = end_pos + 1
414
+ end
415
+
416
+ pending
417
+ end
418
+
419
+ def upload_in_threads(target_directory_key, target_file_key, upload_id, pending, completed, thread_count)
420
+ threads = []
421
+
422
+ thread_count.times do
423
+ thread = Thread.new do
424
+ begin
425
+ while part = pending.shift
426
+ part_upload = service.upload_part_copy(target_directory_key, target_file_key, upload_id, part.part_number, part.upload_options)
427
+ part.etag = part_upload.body['ETag']
428
+ completed.push(part)
429
+ end
430
+ rescue => error
431
+ pending.clear!
432
+ error
433
+ end
434
+ end
435
+
436
+ thread.abort_on_exception = true
437
+ threads << thread
438
+ end
439
+
440
+ threads.map(&:value).compact
441
+ end
321
442
  end
322
443
  end
323
444
  end
@@ -0,0 +1,18 @@
1
+ module Fog
2
+ module Parsers
3
+ module AWS
4
+ module Storage
5
+ class UploadPartCopyObject < Fog::Parsers::Base
6
+ def end_element(name)
7
+ case name
8
+ when 'ETag'
9
+ @response[name] = value.gsub('"', '')
10
+ when 'LastModified'
11
+ @response[name] = Time.parse(value)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -113,7 +113,7 @@ module Fog
113
113
  raise Fog::AWS::Compute::Error.new(message)
114
114
  end
115
115
 
116
- if !image_id.match(/^ami-[a-f0-9]{8}$/)
116
+ if !image_id.match(/^ami-[a-f0-9]{8,17}$/)
117
117
  message = "The image id '[#{image_id}]' does not exist"
118
118
  raise Fog::AWS::Compute::NotFound.new(message)
119
119
  end
@@ -0,0 +1,92 @@
1
+ module Fog
2
+ module AWS
3
+ class Storage
4
+ class Real
5
+ require 'fog/aws/parsers/storage/upload_part_copy_object'
6
+
7
+ # Upload a part for a multipart copy
8
+ #
9
+ # @param target_bucket_name [String] Name of bucket to create copy in
10
+ # @param target_object_name [String] Name for new copy of object
11
+ # @param upload_id [String] Id of upload to add part to
12
+ # @param part_number [String] Index of part in upload
13
+ # @param options [Hash]:
14
+ # @option options [String] x-amz-metadata-directive Specifies whether to copy metadata from source or replace with data in request. Must be in ['COPY', 'REPLACE']
15
+ # @option options [String] x-amz-copy_source-if-match Copies object if its etag matches this value
16
+ # @option options [Time] x-amz-copy_source-if-modified_since Copies object it it has been modified since this time
17
+ # @option options [String] x-amz-copy_source-if-none-match Copies object if its etag does not match this value
18
+ # @option options [Time] x-amz-copy_source-if-unmodified-since Copies object it it has not been modified since this time
19
+ # @option options [Time] x-amz-copy-source-range Specifes the range of bytes to copy from the source object
20
+ #
21
+ # @return [Excon::Response]
22
+ # * body [Hash]:
23
+ # * ETag [String] - etag of new object
24
+ # * LastModified [Time] - date object was last modified
25
+ #
26
+ # @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html
27
+ #
28
+ def upload_part_copy(target_bucket_name, target_object_name, upload_id, part_number, options = {})
29
+ headers = options
30
+ request({
31
+ :expects => 200,
32
+ :idempotent => true,
33
+ :headers => headers,
34
+ :bucket_name => target_bucket_name,
35
+ :object_name => target_object_name,
36
+ :method => 'PUT',
37
+ :query => {'uploadId' => upload_id, 'partNumber' => part_number},
38
+ :parser => Fog::Parsers::AWS::Storage::UploadPartCopyObject.new,
39
+ })
40
+ end
41
+ end # Real
42
+
43
+ class Mock # :nodoc:all
44
+ require 'fog/aws/requests/storage/shared_mock_methods'
45
+ include Fog::AWS::Storage::SharedMockMethods
46
+
47
+ def upload_part_copy(target_bucket_name, target_object_name, upload_id, part_number, options = {})
48
+ copy_source = options['x-amz-copy-source']
49
+ copy_range = options['x-amz-copy-source-range']
50
+
51
+ raise 'No x-amz-copy-source header provided' unless copy_source
52
+ raise 'No x-amz-copy-source-range header provided' unless copy_range
53
+
54
+ source_bucket_name, source_object_name = copy_source.split('/', 2)
55
+ verify_mock_bucket_exists(source_bucket_name)
56
+
57
+ source_bucket = self.data[:buckets][source_bucket_name]
58
+ source_object = source_bucket && source_bucket[:objects][source_object_name] && source_bucket[:objects][source_object_name].first
59
+ upload_info = get_upload_info(target_bucket_name, upload_id)
60
+
61
+ response = Excon::Response.new
62
+
63
+ if source_object
64
+ start_pos, end_pos = byte_range(copy_range, source_object[:body].length)
65
+ upload_info[:parts][part_number] = source_object[:body][start_pos..end_pos]
66
+
67
+ response.status = 200
68
+ response.body = {
69
+ # just use the part number as the ETag, for simplicity
70
+ 'ETag' => part_number.to_i,
71
+ 'LastModified' => Time.parse(source_object['Last-Modified'])
72
+ }
73
+ response
74
+ else
75
+ response.status = 404
76
+ raise(Excon::Errors.status_error({:expects => 200}, response))
77
+ end
78
+ end
79
+
80
+ def byte_range(range, size)
81
+ matches = range.match(/bytes=(\d*)-(\d*)/)
82
+
83
+ return nil unless matches
84
+
85
+ end_pos = [matches[2].to_i, size].min
86
+
87
+ [matches[1].to_i, end_pos]
88
+ end
89
+ end # Mock
90
+ end # Storage
91
+ end # AWS
92
+ end # Fog
@@ -112,6 +112,7 @@ module Fog
112
112
  request :put_request_payment
113
113
  request :sync_clock
114
114
  request :upload_part
115
+ request :upload_part_copy
115
116
 
116
117
  module Utils
117
118
  attr_accessor :region
@@ -1,5 +1,5 @@
1
1
  module Fog
2
2
  module AWS
3
- VERSION = "3.6.7"
3
+ VERSION = "3.7.0"
4
4
  end
5
5
  end
@@ -60,6 +60,35 @@ Shindo.tests('AWS | credentials', ['aws']) do
60
60
 
61
61
  ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'] = nil
62
62
 
63
+ ENV['AWS_WEB_IDENTITY_TOKEN_FILE'] = File.dirname(__FILE__) + '/lorem.txt'
64
+ ENV['AWS_ROLE_ARN'] = "dummyrole"
65
+ ENV['AWS_ROLE_SESSION_NAME'] = "dummyrolesessionname"
66
+ document =
67
+ '<AssumeRoleWithWebIdentityResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">'\
68
+ '<AssumeRoleWithWebIdentityResult>'\
69
+ '<Credentials>'\
70
+ '<SessionToken>dummytoken</SessionToken>'\
71
+ '<SecretAccessKey>dummysecret</SecretAccessKey>'\
72
+ "<Expiration>#{expires_at.xmlschema}</Expiration>"\
73
+ '<AccessKeyId>dummykey</AccessKeyId>'\
74
+ '</Credentials>'\
75
+ '</AssumeRoleWithWebIdentityResult>'\
76
+ '</AssumeRoleWithWebIdentityResponse>'
77
+
78
+ Excon.stub({method: :get, path: "/", idempotent: true}, { status: 200, body: document})
79
+
80
+ tests('#fetch_credentials token based') do
81
+ returns(
82
+ aws_access_key_id: 'dummykey',
83
+ aws_secret_access_key: 'dummysecret',
84
+ aws_session_token: 'dummytoken',
85
+ region: 'us-west-1',
86
+ aws_credentials_expire_at: expires_at
87
+ ) { Fog::AWS::Compute.fetch_credentials(use_iam_profile: true) }
88
+ end
89
+
90
+ ENV['AWS_WEB_IDENTITY_TOKEN_FILE'] = nil
91
+
63
92
  compute = Fog::AWS::Compute.new(use_iam_profile: true)
64
93
 
65
94
  tests('#refresh_credentials_if_expired') do
@@ -100,6 +129,7 @@ Shindo.tests('AWS | credentials', ['aws']) do
100
129
  end
101
130
  ensure
102
131
  ENV['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'] = nil
132
+ ENV['AWS_WEB_IDENTITY_TOKEN_FILE'] = nil
103
133
  Excon.stubs.clear
104
134
  Excon.defaults[:mock] = old_mock_value
105
135
  Fog.mock! if fog_was_mocked
@@ -0,0 +1,80 @@
1
+ require 'securerandom'
2
+
3
+ Shindo.tests('Fog::Storage[:aws] | copy requests', ["aws"]) do
4
+
5
+ @directory = Fog::Storage[:aws].directories.create(:key => uniq_id('fogmultipartcopytests'))
6
+ @large_data = SecureRandom.hex * 19 * 1024 * 1024
7
+ @large_blob = Fog::Storage[:aws].put_object(@directory.identity, 'large_object', @large_data)
8
+
9
+ tests('copies an empty object') do
10
+ Fog::Storage[:aws].put_object(@directory.identity, 'empty_object', '')
11
+
12
+ file = Fog::Storage[:aws].directories.new(key: @directory.identity).files.get('empty_object')
13
+ file.multipart_chunk_size = Fog::AWS::Storage::File::MIN_MULTIPART_CHUNK_SIZE
14
+
15
+ tests("#copy_object('#{@directory.identity}', 'empty_copied_object'").succeeds do
16
+ file.copy(@directory.identity, 'empty_copied_object')
17
+ end
18
+
19
+ copied = Fog::Storage[:aws].directories.new(key: @directory.identity).files.get('empty_copied_object')
20
+ test("copied is the same") { copied.body == file.body }
21
+ end
22
+
23
+ tests('copies a small object') do
24
+ Fog::Storage[:aws].put_object(@directory.identity, 'fog_object', lorem_file)
25
+
26
+ file = Fog::Storage[:aws].directories.new(key: @directory.identity).files.get('fog_object')
27
+
28
+ tests("#copy_object('#{@directory.identity}', 'copied_object'").succeeds do
29
+ file.copy(@directory.identity, 'copied_object')
30
+ end
31
+
32
+ copied = Fog::Storage[:aws].directories.new(key: @directory.identity).files.get('copied_object')
33
+ test("copied is the same") { copied.body == file.body }
34
+ end
35
+
36
+ tests('copies a file needing a single part') do
37
+ data = '*' * Fog::AWS::Storage::File::MIN_MULTIPART_CHUNK_SIZE
38
+ Fog::Storage[:aws].put_object(@directory.identity, '1_part_object', data)
39
+
40
+ file = Fog::Storage[:aws].directories.new(key: @directory.identity).files.get('1_part_object')
41
+ file.multipart_chunk_size = Fog::AWS::Storage::File::MIN_MULTIPART_CHUNK_SIZE
42
+
43
+ tests("#copy_object('#{@directory.identity}', '1_part_copied_object'").succeeds do
44
+ file.copy(@directory.identity, '1_part_copied_object')
45
+ end
46
+
47
+ copied = Fog::Storage[:aws].directories.new(key: @directory.identity).files.get('1_part_copied_object')
48
+ test("copied is the same") { copied.body == file.body }
49
+ end
50
+
51
+ tests('copies a file with many parts') do
52
+ file = Fog::Storage[:aws].directories.new(key: @directory.identity).files.get('large_object')
53
+ file.multipart_chunk_size = Fog::AWS::Storage::File::MIN_MULTIPART_CHUNK_SIZE
54
+
55
+ tests("#copy_object('#{@directory.identity}', 'large_copied_object'").succeeds do
56
+ file.copy(@directory.identity, 'large_copied_object')
57
+ end
58
+
59
+ copied = Fog::Storage[:aws].directories.new(key: @directory.identity).files.get('large_copied_object')
60
+
61
+ test("concurrency defaults to 1") { file.concurrency == 1 }
62
+ test("copied is the same") { copied.body == file.body }
63
+ end
64
+
65
+ tests('copies a file with many parts with 10 threads') do
66
+ file = Fog::Storage[:aws].directories.new(key: @directory.identity).files.get('large_object')
67
+ file.multipart_chunk_size = Fog::AWS::Storage::File::MIN_MULTIPART_CHUNK_SIZE
68
+ file.concurrency = 10
69
+
70
+ test("concurrency is set to 10") { file.concurrency == 10 }
71
+
72
+ tests("#copy_object('#{@directory.identity}', 'copied_object_with_10_threads'").succeeds do
73
+ file.copy(@directory.identity, 'copied_object_with_10_threads')
74
+ end
75
+
76
+ copied = Fog::Storage[:aws].directories.new(key: @directory.identity).files.get('copied_object_with_10_threads')
77
+
78
+ test("copied is the same") { copied.body == file.body }
79
+ end
80
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fog-aws
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.7
4
+ version: 3.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Lane
8
8
  - Wesley Beary
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-08-26 00:00:00.000000000 Z
12
+ date: 2020-12-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -754,6 +754,7 @@ files:
754
754
  - lib/fog/aws/parsers/storage/initiate_multipart_upload.rb
755
755
  - lib/fog/aws/parsers/storage/list_multipart_uploads.rb
756
756
  - lib/fog/aws/parsers/storage/list_parts.rb
757
+ - lib/fog/aws/parsers/storage/upload_part_copy_object.rb
757
758
  - lib/fog/aws/parsers/sts/assume_role.rb
758
759
  - lib/fog/aws/parsers/sts/assume_role_with_saml.rb
759
760
  - lib/fog/aws/parsers/sts/assume_role_with_web_identity.rb
@@ -1442,6 +1443,7 @@ files:
1442
1443
  - lib/fog/aws/requests/storage/shared_mock_methods.rb
1443
1444
  - lib/fog/aws/requests/storage/sync_clock.rb
1444
1445
  - lib/fog/aws/requests/storage/upload_part.rb
1446
+ - lib/fog/aws/requests/storage/upload_part_copy.rb
1445
1447
  - lib/fog/aws/requests/sts/assume_role.rb
1446
1448
  - lib/fog/aws/requests/sts/assume_role_with_saml.rb
1447
1449
  - lib/fog/aws/requests/sts/assume_role_with_web_identity.rb
@@ -1709,6 +1711,7 @@ files:
1709
1711
  - tests/requests/storage/bucket_tests.rb
1710
1712
  - tests/requests/storage/cors_utils_tests.rb
1711
1713
  - tests/requests/storage/delete_multiple_objects_tests.rb
1714
+ - tests/requests/storage/multipart_copy_tests.rb
1712
1715
  - tests/requests/storage/multipart_upload_tests.rb
1713
1716
  - tests/requests/storage/object_tests.rb
1714
1717
  - tests/requests/storage/versioning_tests.rb
@@ -1726,7 +1729,7 @@ homepage: https://github.com/fog/fog-aws
1726
1729
  licenses:
1727
1730
  - MIT
1728
1731
  metadata: {}
1729
- post_install_message:
1732
+ post_install_message:
1730
1733
  rdoc_options: []
1731
1734
  require_paths:
1732
1735
  - lib
@@ -1741,8 +1744,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1741
1744
  - !ruby/object:Gem::Version
1742
1745
  version: '0'
1743
1746
  requirements: []
1744
- rubygems_version: 3.0.3
1745
- signing_key:
1747
+ rubygems_version: 3.1.2
1748
+ signing_key:
1746
1749
  specification_version: 4
1747
1750
  summary: Module for the 'fog' gem to support Amazon Web Services.
1748
1751
  test_files: []