fog-aws 3.6.7 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []