parent
cce5d313b3
commit
d54caaaa02
31
go.mod
31
go.mod
|
|
@ -5,7 +5,10 @@ go 1.17
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/storage v1.30.1
|
cloud.google.com/go/storage v1.30.1
|
||||||
github.com/Azure/azure-storage-blob-go v0.14.0
|
github.com/Azure/azure-storage-blob-go v0.14.0
|
||||||
github.com/aws/aws-sdk-go v1.44.253
|
github.com/aws/aws-sdk-go-v2 v1.18.0
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.18.25
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.67
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1
|
||||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795
|
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795
|
||||||
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589
|
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589
|
||||||
github.com/containerd/cgroups v1.1.0 // indirect
|
github.com/containerd/cgroups v1.1.0 // indirect
|
||||||
|
|
@ -58,17 +61,21 @@ require (
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect
|
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect
|
||||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||||
github.com/agext/levenshtein v1.2.3 // indirect
|
github.com/agext/levenshtein v1.2.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.3 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.15.5 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.24 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.0 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 // indirect
|
||||||
github.com/aws/smithy-go v1.11.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 // indirect
|
||||||
|
github.com/aws/smithy-go v1.13.5 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/cilium/ebpf v0.9.1 // indirect
|
github.com/cilium/ebpf v0.9.1 // indirect
|
||||||
|
|
|
||||||
67
go.sum
67
go.sum
|
|
@ -98,49 +98,63 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/aws/aws-sdk-go v1.44.253 h1:iqDd0okcH4ShfFexz2zzf4VmeDFf6NOMm07pHnEb8iY=
|
|
||||||
github.com/aws/aws-sdk-go v1.44.253/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
|
||||||
github.com/aws/aws-sdk-go-v2 v1.7.1/go.mod h1:L5LuPC1ZgDr2xQS7AmIec/Jlc7O/Y1u2KxJyNVab250=
|
github.com/aws/aws-sdk-go-v2 v1.7.1/go.mod h1:L5LuPC1ZgDr2xQS7AmIec/Jlc7O/Y1u2KxJyNVab250=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.14.0/go.mod h1:ZA3Y8V0LrlWj63MQAnRHgKf/5QB//LSZCPNWlWrNGLU=
|
github.com/aws/aws-sdk-go-v2 v1.14.0/go.mod h1:ZA3Y8V0LrlWj63MQAnRHgKf/5QB//LSZCPNWlWrNGLU=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.3 h1:0W1TSJ7O6OzwuEvIXAtJGvOeQ0SGAhcpxPN2/NK5EhM=
|
github.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.3/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
|
github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||||
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
|
||||||
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.5.0/go.mod h1:RWlPOAW3E3tbtNAqTwvSW54Of/yP3oiZXMI0xfUdjyA=
|
github.com/aws/aws-sdk-go-v2/config v1.5.0/go.mod h1:RWlPOAW3E3tbtNAqTwvSW54Of/yP3oiZXMI0xfUdjyA=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.15.5 h1:P+xwhr6kabhxDTXTVH9YoHkqjLJ0wVVpIUHtFNr2hjU=
|
github.com/aws/aws-sdk-go-v2/config v1.18.25 h1:JuYyZcnMPBiFqn87L2cRppo+rNwgah6YwD3VuyvaW6Q=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.15.5/go.mod h1:ZijHHh0xd/A+ZY53az0qzC5tT46kt4JVCePf2NX9Lk4=
|
github.com/aws/aws-sdk-go-v2/config v1.18.25/go.mod h1:dZnYpD5wTW/dQF0rRNLVypB396zWCcPiBIvdvSWHEg4=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.3.1/go.mod h1:r0n73xwsIVagq8RsxmZbGSRQFj9As3je72C2WzUIToc=
|
github.com/aws/aws-sdk-go-v2/credentials v1.3.1/go.mod h1:r0n73xwsIVagq8RsxmZbGSRQFj9As3je72C2WzUIToc=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.0 h1:4R/NqlcRFSkR0wxOhgHi+agGpbEr5qMCjn7VqUIJY+E=
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.24 h1:PjiYyls3QdCrzqUN35jMWtUK1vqVZ+zLfdOa/UPFDp0=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.0/go.mod h1:9YWk7VW+eyKsoIL6/CljkTrNVWBSK9pkqOPUuijid4A=
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.24/go.mod h1:jYPYi99wUOPIFi0rhiOvXeSEReVOzBqFNOX5bXYoG2o=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.3.0/go.mod h1:2LAuqPx1I6jNfaGDucWfA2zqQCYCOMCDHiCOciALyNw=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.3.0/go.mod h1:2LAuqPx1I6jNfaGDucWfA2zqQCYCOMCDHiCOciALyNw=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 h1:FP8gquGeGHHdfY6G5llaMQDF+HAf20VKc8opRwmjf04=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 h1:jJPgroehGvjrde3XufFIJUZVK5A2L9a3KwSFgKy9n8w=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4/go.mod h1:u/s5/Z+ohUQOPXl00m2yJVyioWDECsbpXTQlaqSlufc=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3/go.mod h1:4Q0UFP0YJf0NrsEuEYHpM9fTSEVnD16Z3uyEF7J9JGM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.67 h1:fI9/5BDEaAv/pv1VO1X1n3jfP9it+IGqWsCuuBQI8wM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.67/go.mod h1:zQClPRIwQZfJlZq6WZve+s4Tb4JW+3V6eS+4+KrYeP8=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.5/go.mod h1:2hXc8ooJqF2nAznsbJQIn+7h851/bu8GVC80OVTTqf8=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.5/go.mod h1:2hXc8ooJqF2nAznsbJQIn+7h851/bu8GVC80OVTTqf8=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 h1:uFWgo6mGJI1n17nbcvSc6fxVuR3xLNqvXt12JCnEcT8=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 h1:kG5eQilShqmJbv11XL1VpyDbaEJzWxd4zRiCG30GSn4=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10/go.mod h1:F+EZtuIwjlv35kRJPyBGcsA4f7bnSoz15zOQ2lJq1Z4=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.3.0/go.mod h1:miRSv9l093jX/t/j+mBCaLqFHo9xKYzJ7DGm1BsGoJM=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.3.0/go.mod h1:miRSv9l093jX/t/j+mBCaLqFHo9xKYzJ7DGm1BsGoJM=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4 h1:cnsvEKSoHN4oAN7spMMr0zhEW2MHnhAVpmqQg8E6UcM=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 h1:vFQlirhuM8lLlpI7imKOMsjdQLuN9CPi+k44F/OFVsk=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4/go.mod h1:8glyUqVIM4AmeenIsPo0oVh3+NUwnsQml2OFupfQW+0=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.1.1/go.mod h1:Zy8smImhTdOETZqfyn01iNOe0CNggVbPjCajyaz6Gvg=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.1.1/go.mod h1:Zy8smImhTdOETZqfyn01iNOe0CNggVbPjCajyaz6Gvg=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 h1:6cZRymlLEIlDTEB0+5+An6Zj1CKt6rSE69tOmFeu1nk=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 h1:gGLG7yKaXG02/jBlg210R7VgQIotiQntNhsCFejawx8=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11/go.mod h1:0MR+sS1b/yxsfAPvAESrw8NfwUoxMinDyw6EYR9BS2U=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34/go.mod h1:Etz2dj6UHYuw+Xw830KfzCfWGMzqvUTCjUj5b76GVDc=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25 h1:AzwRi5OKKwo4QNqPf7TjeO+tK8AyOK3GVSwmRPo7/Cs=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25/go.mod h1:SUbB4wcbSEyCvqBxv/O/IBf93RbEze7U7OnoTlpPB+g=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.4.1/go.mod h1:FglZcyeiBqcbvyinl+n14aT/EWC7S1MIH+Gan2iizt0=
|
github.com/aws/aws-sdk-go-v2/service/ecr v1.4.1/go.mod h1:FglZcyeiBqcbvyinl+n14aT/EWC7S1MIH+Gan2iizt0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0 h1:lY2Z2sBP+zSbJ6CvvmnFgPcgknoQ0OJV88AwVetRRFk=
|
github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0 h1:lY2Z2sBP+zSbJ6CvvmnFgPcgknoQ0OJV88AwVetRRFk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0/go.mod h1:4zYI85WiYDhFaU1jPFVfkD7HlBcdnITDE3QxDwy4Kus=
|
github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0/go.mod h1:4zYI85WiYDhFaU1jPFVfkD7HlBcdnITDE3QxDwy4Kus=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.4.1/go.mod h1:eD5Eo4drVP2FLTw0G+SMIPWNWvQRGGTtIZR2XeAagoA=
|
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.4.1/go.mod h1:eD5Eo4drVP2FLTw0G+SMIPWNWvQRGGTtIZR2XeAagoA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.12.0 h1:LsqBpyRofMG6eDs6YGud6FhdGyIyXelAasPOZ6wWLro=
|
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.12.0 h1:LsqBpyRofMG6eDs6YGud6FhdGyIyXelAasPOZ6wWLro=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.12.0/go.mod h1:IArQ3IBR00FkuraKwudKZZU32OxJfdTdwV+W5iZh3Y4=
|
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.12.0/go.mod h1:IArQ3IBR00FkuraKwudKZZU32OxJfdTdwV+W5iZh3Y4=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28 h1:vGWm5vTpMr39tEZfQeDiDAMgk+5qsnvRny3FjLpnH5w=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28/go.mod h1:spfrICMD6wCAhjhzHuy6DOZZ+LAIY10UxhUmLzpJTTs=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.2.1/go.mod h1:zceowr5Z1Nh2WVP8bf/3ikB41IZW59E4yIYbg+pC6mw=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.2.1/go.mod h1:zceowr5Z1Nh2WVP8bf/3ikB41IZW59E4yIYbg+pC6mw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4 h1:b16QW0XWl0jWjLABFc1A+uh145Oqv+xDcObNk0iQgUk=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 h1:0iKliEXAcCa2qVtRs7Ot5hItA2MsufrphbRFlz1Owxo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4/go.mod h1:uKkN7qmSIsNJVyMtxNQoCEYMvFEXbOg9fwCJPdfp2u8=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27/go.mod h1:EOwBD4J4S5qYszS5/3DpkejfuK+Z5/1uzICfPaZLtqw=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2 h1:NbWkRxEEIRSCqxhsHQuMiTH7yo+JZW1gp8v3elSVMTQ=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2/go.mod h1:4tfW5l4IAB32VWCDEBxCRtR9T4BWy4I4kr1spr8NgZM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1 h1:O+9nAy9Bb6bJFTpeNFtd9UfHbgxO1o4ZDAM9rQp5NsY=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1/go.mod h1:J9kLNzEiHSeGMyN7238EjJmBpCniVzFda75Gxl/NqB8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.3.1/go.mod h1:J3A3RGUvuCZjvSuZEcOpHDnzZP/sKbhDWV2T1EOzFIM=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.3.1/go.mod h1:J3A3RGUvuCZjvSuZEcOpHDnzZP/sKbhDWV2T1EOzFIM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 h1:Uw5wBybFQ1UeA9ts0Y07gbv0ncZnIAyw858tDW0NP2o=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 h1:UBQjaMTCKwyUYwiVnUt6toEJwGXsLBI6al083tpjJzY=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.4/go.mod h1:cPDwJwsP4Kff9mldCXAmddjJL6JGQqtA3Mzer2zyr88=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.12.10/go.mod h1:ouy2P4z6sJN70fR3ka3wD3Ro3KezSxU6eKGQI2+2fjI=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 h1:PkHIIJs8qvq0e5QybnZoG1K/9QTrLr9OsqCIo59jOBA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10/go.mod h1:AFvkxc8xfBe8XA+5St5XIHHrQQtkxqrRincx4hmMHOk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.6.0/go.mod h1:q7o0j7d7HrJk/vr9uUt3BVRASvcU7gYZB9PUgPiByXg=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.6.0/go.mod h1:q7o0j7d7HrJk/vr9uUt3BVRASvcU7gYZB9PUgPiByXg=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 h1:+xtV90n3abQmgzk1pS++FdxZTrPEDgQng6e4/56WR2A=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 h1:2DQLAKDteoEDI8zpCzqBMaZlJuoE9iTYD0gFmXVax9E=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.4/go.mod h1:lfSYenAXtavyX2A1LsViglqlG9eEFYxNryTZS5rn3QE=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.19.0/go.mod h1:BgQOMsg8av8jset59jelyPW7NoZcZXLVpDsXunGDrk8=
|
||||||
github.com/aws/smithy-go v1.6.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
github.com/aws/smithy-go v1.6.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||||
github.com/aws/smithy-go v1.11.0/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
|
github.com/aws/smithy-go v1.11.0/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
|
||||||
github.com/aws/smithy-go v1.11.2 h1:eG/N+CcUMAvsdffgMvjMKwfyDzIkjM6pfxMJ8Mzc6mE=
|
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
|
||||||
github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
|
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795 h1:IWeCJzU+IYaO2rVEBlGPTBfe90cmGXFTLdhUFlzDGsY=
|
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795 h1:IWeCJzU+IYaO2rVEBlGPTBfe90cmGXFTLdhUFlzDGsY=
|
||||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795/go.mod h1:8vJsEZ4iRqG+Vx6pKhWK6U00qcj0KC37IsfszMkY6UE=
|
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795/go.mod h1:8vJsEZ4iRqG+Vx6pKhWK6U00qcj0KC37IsfszMkY6UE=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
|
@ -319,6 +333,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||||
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-containerregistry v0.15.1 h1:RsJ9NbfxYWF8Wl4VmvkpN3zYATwuvlPq2j20zmcs63E=
|
github.com/google/go-containerregistry v0.15.1 h1:RsJ9NbfxYWF8Wl4VmvkpN3zYATwuvlPq2j20zmcs63E=
|
||||||
|
|
@ -683,7 +698,6 @@ golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
|
|
@ -781,7 +795,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
@ -789,7 +802,6 @@ golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
||||||
|
|
@ -802,7 +814,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
package buildcontext
|
package buildcontext
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -26,10 +27,10 @@ import (
|
||||||
"github.com/GoogleContainerTools/kaniko/pkg/constants"
|
"github.com/GoogleContainerTools/kaniko/pkg/constants"
|
||||||
"github.com/GoogleContainerTools/kaniko/pkg/util"
|
"github.com/GoogleContainerTools/kaniko/pkg/util"
|
||||||
"github.com/GoogleContainerTools/kaniko/pkg/util/bucket"
|
"github.com/GoogleContainerTools/kaniko/pkg/util/bucket"
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go-v2/config"
|
||||||
"github.com/aws/aws-sdk-go/service/s3"
|
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// S3 unifies calls to download and unpack the build context.
|
// S3 unifies calls to download and unpack the build context.
|
||||||
|
|
@ -44,25 +45,31 @@ func (s *S3) UnpackTarFromBuildContext() (string, error) {
|
||||||
return "", fmt.Errorf("getting bucketname and filepath from context: %w", err)
|
return "", fmt.Errorf("getting bucketname and filepath from context: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
option := session.Options{
|
|
||||||
SharedConfigState: session.SharedConfigEnable,
|
|
||||||
}
|
|
||||||
endpoint := os.Getenv(constants.S3EndpointEnv)
|
endpoint := os.Getenv(constants.S3EndpointEnv)
|
||||||
forcePath := false
|
forcePath := false
|
||||||
if strings.ToLower(os.Getenv(constants.S3ForcePathStyle)) == "true" {
|
if strings.ToLower(os.Getenv(constants.S3ForcePathStyle)) == "true" {
|
||||||
forcePath = true
|
forcePath = true
|
||||||
}
|
}
|
||||||
if endpoint != "" {
|
|
||||||
option.Config = aws.Config{
|
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
|
||||||
Endpoint: aws.String(endpoint),
|
if endpoint != "" {
|
||||||
S3ForcePathStyle: aws.Bool(forcePath),
|
return aws.Endpoint{
|
||||||
|
URL: endpoint,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
}
|
return aws.Endpoint{}, &aws.EndpointNotFoundError{}
|
||||||
sess, err := session.NewSessionWithOptions(option)
|
})
|
||||||
|
|
||||||
|
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithEndpointResolverWithOptions(customResolver))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bucket, err
|
return bucket, err
|
||||||
}
|
}
|
||||||
downloader := s3manager.NewDownloader(sess)
|
client := s3.NewFromConfig(cfg, func(options *s3.Options) {
|
||||||
|
if endpoint != "" {
|
||||||
|
options.UsePathStyle = forcePath
|
||||||
|
}
|
||||||
|
})
|
||||||
|
downloader := s3manager.NewDownloader(client)
|
||||||
directory := kConfig.BuildContextDir
|
directory := kConfig.BuildContextDir
|
||||||
tarPath := filepath.Join(directory, constants.ContextTar)
|
tarPath := filepath.Join(directory, constants.ContextTar)
|
||||||
if err := os.MkdirAll(directory, 0750); err != nil {
|
if err := os.MkdirAll(directory, 0750); err != nil {
|
||||||
|
|
@ -72,7 +79,7 @@ func (s *S3) UnpackTarFromBuildContext() (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return directory, err
|
return directory, err
|
||||||
}
|
}
|
||||||
_, err = downloader.Download(file,
|
_, err = downloader.Download(context.TODO(), file,
|
||||||
&s3.GetObjectInput{
|
&s3.GetObjectInput{
|
||||||
Bucket: aws.String(bucket),
|
Bucket: aws.String(bucket),
|
||||||
Key: aws.String(item),
|
Key: aws.String(item),
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,6 @@ Gemfile.lock
|
||||||
/private/model/cli/gen-api/gen-api
|
/private/model/cli/gen-api/gen-api
|
||||||
.gradle/
|
.gradle/
|
||||||
build/
|
build/
|
||||||
|
.idea/
|
||||||
|
bin/
|
||||||
|
.vscode/
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ modules-download-mode = "readonly"
|
||||||
allow-parallel-runners = true
|
allow-parallel-runners = true
|
||||||
skip-dirs = ["internal/repotools"]
|
skip-dirs = ["internal/repotools"]
|
||||||
skip-dirs-use-default = true
|
skip-dirs-use-default = true
|
||||||
|
skip-files = ["service/transcribestreaming/eventstream_test.go"]
|
||||||
[output]
|
[output]
|
||||||
format = "github-actions"
|
format = "github-actions"
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,4 +1,4 @@
|
||||||
## Code of Conduct
|
## Code of Conduct
|
||||||
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||||
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||||
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
||||||
|
|
|
||||||
|
|
@ -14,29 +14,28 @@ Jump To:
|
||||||
* [Feature Requests](#feature-requests)
|
* [Feature Requests](#feature-requests)
|
||||||
* [Code Contributions](#code-contributions)
|
* [Code Contributions](#code-contributions)
|
||||||
|
|
||||||
|
|
||||||
## How to contribute
|
## How to contribute
|
||||||
|
|
||||||
*Before you send us a pull request, please be sure that:*
|
*Before you send us a pull request, please be sure that:*
|
||||||
|
|
||||||
1. You're working from the latest source on the master branch.
|
1. You're working from the latest source on the `main` branch.
|
||||||
2. You check existing open, and recently closed, pull requests to be sure
|
2. You check existing open, and recently closed, pull requests to be sure
|
||||||
that someone else hasn't already addressed the problem.
|
that someone else hasn't already addressed the problem.
|
||||||
3. You create an issue before working on a contribution that will take a
|
3. You create an issue before working on a contribution that will take a
|
||||||
significant amount of your time.
|
significant amount of your time.
|
||||||
|
|
||||||
*Creating a Pull Request*
|
*Creating a Pull Request*
|
||||||
|
|
||||||
1. Fork the repository.
|
1. Fork the repository.
|
||||||
2. In your fork, make your change in a branch that's based on this repo's master branch.
|
2. In your fork, make your change in a branch that's based on this repo's `main` branch.
|
||||||
3. Commit the change to your fork, using a clear and descriptive commit message.
|
3. Commit the change to your fork, using a clear and descriptive commit message.
|
||||||
4. Create a pull request, answering any questions in the pull request form.
|
4. Create a pull request, answering any questions in the pull request form.
|
||||||
|
|
||||||
For contributions that will take a significant amount of time, open a new
|
For contributions that will take a significant amount of time, open a new
|
||||||
issue to pitch your idea before you get started. Explain the problem and
|
issue to pitch your idea before you get started. Explain the problem and
|
||||||
describe the content you want to see added to the documentation. Let us know
|
describe the content you want to see added to the documentation. Let us know
|
||||||
if you'll write it yourself or if you'd like us to help. We'll discuss your
|
if you'll write it yourself or if you'd like us to help. We'll discuss your
|
||||||
proposal with you and let you know whether we're likely to accept it.
|
proposal with you and let you know whether we're likely to accept it.
|
||||||
|
|
||||||
## Bug Reports
|
## Bug Reports
|
||||||
|
|
||||||
|
|
@ -74,9 +73,9 @@ guidelines prior to filing a bug report.
|
||||||
|
|
||||||
Open an [issue][issues] with the following:
|
Open an [issue][issues] with the following:
|
||||||
|
|
||||||
* A short, descriptive title. Ideally, other community members should be able
|
* A short, descriptive title. Ideally, other community members should be able
|
||||||
to get a good idea of the feature just from reading the title.
|
to get a good idea of the feature just from reading the title.
|
||||||
* A detailed description of the the proposed feature.
|
* A detailed description of the the proposed feature.
|
||||||
* Why it should be added to the SDK.
|
* Why it should be added to the SDK.
|
||||||
* If possible, example code to illustrate how it should work.
|
* If possible, example code to illustrate how it should work.
|
||||||
* Use Markdown to make the request easier to read;
|
* Use Markdown to make the request easier to read;
|
||||||
|
|
@ -97,7 +96,7 @@ Please be aware of the following notes prior to opening a pull request:
|
||||||
|
|
||||||
3. Wherever possible, pull requests should contain tests as appropriate.
|
3. Wherever possible, pull requests should contain tests as appropriate.
|
||||||
Bugfixes should contain tests that exercise the corrected behavior (i.e., the
|
Bugfixes should contain tests that exercise the corrected behavior (i.e., the
|
||||||
test should fail without the bugfix and pass with it), and new features
|
test should fail without the bugfix and pass with it), and new features
|
||||||
should be accompanied by tests exercising the feature.
|
should be accompanied by tests exercising the feature.
|
||||||
|
|
||||||
4. Pull requests that contain failing tests will not be merged until the test
|
4. Pull requests that contain failing tests will not be merged until the test
|
||||||
|
|
@ -112,7 +111,7 @@ Please be aware of the following notes prior to opening a pull request:
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
To run the tests locally, running the `make unit` command will `go get` the
|
To run the tests locally, running the `make unit` command will `go get` the
|
||||||
SDK's testing dependencies, and run vet, link and unit tests for the SDK.
|
SDK's testing dependencies, and run vet, link and unit tests for the SDK.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -129,7 +128,7 @@ go test -tags codegen ./private/...
|
||||||
|
|
||||||
See the `Makefile` for additional testing tags that can be used in testing.
|
See the `Makefile` for additional testing tags that can be used in testing.
|
||||||
|
|
||||||
To test on multiple platform the SDK includes several DockerFiles under the
|
To test on multiple platform the SDK includes several DockerFiles under the
|
||||||
`awstesting/sandbox` folder, and associated make recipes to to execute
|
`awstesting/sandbox` folder, and associated make recipes to to execute
|
||||||
unit testing within environments configured for specific Go versions.
|
unit testing within environments configured for specific Go versions.
|
||||||
|
|
||||||
|
|
@ -170,9 +169,9 @@ This will result in a patch version change.
|
||||||
* `SDK Bugs` - For minor changes that resolve an issue. This will result in a
|
* `SDK Bugs` - For minor changes that resolve an issue. This will result in a
|
||||||
patch version change.
|
patch version change.
|
||||||
|
|
||||||
[issues]: https://github.com/aws/aws-sdk-go/issues
|
[issues]: https://github.com/aws/aws-sdk-go-v2/issues
|
||||||
[pr]: https://github.com/aws/aws-sdk-go/pulls
|
[pr]: https://github.com/aws/aws-sdk-go-v2/pulls
|
||||||
[license]: http://aws.amazon.com/apache2.0/
|
[license]: http://aws.amazon.com/apache2.0/
|
||||||
[cla]: http://en.wikipedia.org/wiki/Contributor_License_Agreement
|
[cla]: http://en.wikipedia.org/wiki/Contributor_License_Agreement
|
||||||
[releasenotes]: https://github.com/aws/aws-sdk-go/releases
|
[releasenotes]: https://github.com/aws/aws-sdk-go-v2/releases
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,4 @@ Past Discussions
|
||||||
---
|
---
|
||||||
The issues listed here are for documentation purposes, and is used to capture issues and their associated discussions.
|
The issues listed here are for documentation purposes, and is used to capture issues and their associated discussions.
|
||||||
|
|
||||||
[Code of Conduct]: https://github.com/aws/aws-sdk-go-v2/blob/master/CODE_OF_CONDUCT.md
|
[Code of Conduct]: https://github.com/aws/aws-sdk-go-v2/blob/main/CODE_OF_CONDUCT.md
|
||||||
|
|
|
||||||
|
|
@ -72,22 +72,22 @@ all: generate unit
|
||||||
# Code Generation #
|
# Code Generation #
|
||||||
###################
|
###################
|
||||||
.PHONY: generate smithy-generate smithy-build smithy-build-% smithy-clean smithy-go-publish-local format \
|
.PHONY: generate smithy-generate smithy-build smithy-build-% smithy-clean smithy-go-publish-local format \
|
||||||
gen-config-asserts gen-repo-mod-replace gen-mod-replace-smithy gen-mod-dropreplace-smithy gen-aws-ptrs tidy-modules-% \
|
gen-config-asserts gen-repo-mod-replace gen-mod-replace-smithy gen-mod-dropreplace-smithy-% gen-aws-ptrs tidy-modules-% \
|
||||||
add-module-license-files sync-models sync-endpoints-model sync-endpoints.json clone-v1-models gen-internal-codegen \
|
add-module-license-files sync-models sync-endpoints-model sync-endpoints.json clone-v1-models gen-internal-codegen \
|
||||||
sync-api-models copy-attributevalue-feature min-go-version-% update-requires smithy-annotate-stable \
|
sync-api-models copy-attributevalue-feature min-go-version-% update-requires smithy-annotate-stable \
|
||||||
update-module-metadata download-modules-%
|
update-module-metadata download-modules-%
|
||||||
|
|
||||||
generate: smithy-generate update-requires gen-repo-mod-replace update-module-metadata smithy-annotate-stable \
|
generate: smithy-generate update-requires gen-repo-mod-replace update-module-metadata smithy-annotate-stable \
|
||||||
gen-config-asserts gen-internal-codegen copy-attributevalue-feature gen-mod-dropreplace-smithy min-go-version-. \
|
gen-config-asserts gen-internal-codegen copy-attributevalue-feature gen-mod-dropreplace-smithy-. min-go-version-. \
|
||||||
tidy-modules-. add-module-license-files gen-aws-ptrs format
|
tidy-modules-. add-module-license-files gen-aws-ptrs format
|
||||||
|
|
||||||
smithy-generate:
|
smithy-generate:
|
||||||
cd codegen && ./gradlew clean build -Plog-tests && ./gradlew clean
|
cd codegen && ./gradlew clean build -Plog-tests && ./gradlew clean
|
||||||
|
|
||||||
smithy-build: gen-repo-mod-replace
|
smithy-build:
|
||||||
cd codegen && ./gradlew clean build -Plog-tests
|
cd codegen && ./gradlew clean build -Plog-tests
|
||||||
|
|
||||||
smithy-build-%: gen-repo-mod-replace
|
smithy-build-%:
|
||||||
@# smithy-build- command that uses the pattern to define build filter that
|
@# smithy-build- command that uses the pattern to define build filter that
|
||||||
@# the smithy API model service id starts with. Strips off the
|
@# the smithy API model service id starts with. Strips off the
|
||||||
@# "smithy-build-".
|
@# "smithy-build-".
|
||||||
|
|
@ -120,19 +120,32 @@ gen-config-asserts:
|
||||||
gen-internal-codegen:
|
gen-internal-codegen:
|
||||||
@echo "Generating internal/codegen"
|
@echo "Generating internal/codegen"
|
||||||
cd internal/codegen \
|
cd internal/codegen \
|
||||||
|
&& go mod tidy \
|
||||||
&& go generate
|
&& go generate
|
||||||
|
|
||||||
gen-repo-mod-replace:
|
gen-repo-mod-replace:
|
||||||
@echo "Generating go.mod replace for repo modules"
|
@echo "Generating go.mod replace for repo modules"
|
||||||
go run ${REPOTOOLS_CMD_MAKE_RELATIVE}
|
go run ${REPOTOOLS_CMD_MAKE_RELATIVE}
|
||||||
|
|
||||||
gen-mod-replace-smithy:
|
gen-mod-replace-smithy-%:
|
||||||
|
@# gen-mod-replace-smithy- command that uses the pattern to define build filter that
|
||||||
|
@# for modules to add replace to. Strips off the "gen-mod-replace-smithy-".
|
||||||
|
@#
|
||||||
|
@# SMITHY_GO_SRC environment variable is the path to add replace to
|
||||||
|
@#
|
||||||
|
@# e.g. gen-mod-replace-smithy-service_ssooidc
|
||||||
cd ./internal/repotools/cmd/eachmodule \
|
cd ./internal/repotools/cmd/eachmodule \
|
||||||
&& go run . "go mod edit -replace github.com/aws/smithy-go=${SMITHY_GO_SRC}"
|
&& go run . -p $(subst _,/,$(subst gen-mod-replace-smithy-,,$@)) ${EACHMODULE_FLAGS} \
|
||||||
|
"go mod edit -replace github.com/aws/smithy-go=${SMITHY_GO_SRC}"
|
||||||
|
|
||||||
gen-mod-dropreplace-smithy:
|
gen-mod-dropreplace-smithy-%:
|
||||||
|
@# gen-mod-dropreplace-smithy- command that uses the pattern to define build filter that
|
||||||
|
@# for modules to add replace to. Strips off the "gen-mod-dropreplace-smithy-".
|
||||||
|
@#
|
||||||
|
@# e.g. gen-mod-dropreplace-smithy-service_ssooidc
|
||||||
cd ./internal/repotools/cmd/eachmodule \
|
cd ./internal/repotools/cmd/eachmodule \
|
||||||
&& go run . "go mod edit -dropreplace github.com/aws/smithy-go"
|
&& go run . -p $(subst _,/,$(subst gen-mod-dropreplace-smithy-,,$@)) ${EACHMODULE_FLAGS} \
|
||||||
|
"go mod edit -dropreplace github.com/aws/smithy-go"
|
||||||
|
|
||||||
gen-aws-ptrs:
|
gen-aws-ptrs:
|
||||||
cd aws && go generate
|
cd aws && go generate
|
||||||
|
|
@ -233,7 +246,6 @@ unit-race-modules-%:
|
||||||
"go test ${BUILD_TAGS} ${RUN_NONE} ./..." \
|
"go test ${BUILD_TAGS} ${RUN_NONE} ./..." \
|
||||||
"go test -timeout=1m ${UNIT_TEST_TAGS} -race -cpu=4 ./..."
|
"go test -timeout=1m ${UNIT_TEST_TAGS} -race -cpu=4 ./..."
|
||||||
|
|
||||||
|
|
||||||
unit-modules-%:
|
unit-modules-%:
|
||||||
@# unit command that uses the pattern to define the root path that the
|
@# unit command that uses the pattern to define the root path that the
|
||||||
@# module testing will start from. Strips off the "unit-modules-" and
|
@# module testing will start from. Strips off the "unit-modules-" and
|
||||||
|
|
@ -395,7 +407,6 @@ bench-modules-%:
|
||||||
&& go run . -p $(subst _,/,$(subst bench-modules-,,$@)) ${EACHMODULE_FLAGS} \
|
&& go run . -p $(subst _,/,$(subst bench-modules-,,$@)) ${EACHMODULE_FLAGS} \
|
||||||
"go test -timeout=10m -bench . --benchmem ${BUILD_TAGS} ${RUN_NONE} ./..."
|
"go test -timeout=10m -bench . --benchmem ${BUILD_TAGS} ${RUN_NONE} ./..."
|
||||||
|
|
||||||
|
|
||||||
#####################
|
#####################
|
||||||
# Release Process #
|
# Release Process #
|
||||||
#####################
|
#####################
|
||||||
|
|
@ -486,14 +497,22 @@ list-deps-%:
|
||||||
###################
|
###################
|
||||||
.PHONY: sandbox-tests sandbox-build-% sandbox-run-% sandbox-test-% update-aws-golang-tip
|
.PHONY: sandbox-tests sandbox-build-% sandbox-run-% sandbox-test-% update-aws-golang-tip
|
||||||
|
|
||||||
sandbox-tests: sandbox-test-go1.15 sandbox-test-go1.16 sandbox-test-go1.17 sandbox-test-gotip
|
sandbox-tests: sandbox-test-go1.15 sandbox-test-go1.16 sandbox-test-go1.17 sandbox-test-go1.18 sandbox-test-go1.19 sandbox-test-go1.20 sandbox-test-gotip
|
||||||
|
|
||||||
sandbox-build-%:
|
sandbox-build-%:
|
||||||
@# sandbox-build-go1.17
|
@# sandbox-build-go1.17
|
||||||
@# sandbox-build-gotip
|
@# sandbox-build-gotip
|
||||||
docker build \
|
@if [ $@ == sandbox-build-gotip ]; then\
|
||||||
-f ./internal/awstesting/sandbox/Dockerfile.test.$(subst sandbox-build-,,$@) \
|
docker build \
|
||||||
-t "aws-sdk-go-$(subst sandbox-build-,,$@)" .
|
-f ./internal/awstesting/sandbox/Dockerfile.test.gotip \
|
||||||
|
-t "aws-sdk-go-$(subst sandbox-build-,,$@)" . ;\
|
||||||
|
else\
|
||||||
|
docker build \
|
||||||
|
--build-arg GO_VERSION=$(subst sandbox-build-go,,$@) \
|
||||||
|
-f ./internal/awstesting/sandbox/Dockerfile.test.goversion \
|
||||||
|
-t "aws-sdk-go-$(subst sandbox-build-,,$@)" . ;\
|
||||||
|
fi
|
||||||
|
|
||||||
sandbox-run-%: sandbox-build-%
|
sandbox-run-%: sandbox-build-%
|
||||||
@# sandbox-run-go1.17
|
@# sandbox-run-go1.17
|
||||||
@# sandbox-run-gotip
|
@# sandbox-run-gotip
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
AWS SDK for Go
|
AWS SDK for Go
|
||||||
Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
Copyright 2014-2015 Stripe, Inc.
|
Copyright 2014-2015 Stripe, Inc.
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
# AWS SDK for Go v2
|
# AWS SDK for Go v2
|
||||||
|
|
||||||
[](https://github.com/aws/aws-sdk-go-v2/actions/workflows/go.yml)[](https://github.com/aws/aws-sdk-go-v2/actions/workflows/codegen.yml) [](https://aws.github.io/aws-sdk-go-v2/docs/) [](https://aws.github.io/aws-sdk-go-v2/docs/migrating/) [](https://pkg.go.dev/mod/github.com/aws/aws-sdk-go-v2) [](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
|
[](https://github.com/aws/aws-sdk-go-v2/actions/workflows/go.yml)[](https://github.com/aws/aws-sdk-go-v2/actions/workflows/codegen.yml) [](https://aws.github.io/aws-sdk-go-v2/docs/) [](https://aws.github.io/aws-sdk-go-v2/docs/migrating/) [](https://pkg.go.dev/mod/github.com/aws/aws-sdk-go-v2) [](https://github.com/aws/aws-sdk-go-v2/blob/main/LICENSE.txt)
|
||||||
|
|
||||||
|
|
||||||
`aws-sdk-go-v2` is the v2 AWS SDK for the Go programming language.
|
`aws-sdk-go-v2` is the v2 AWS SDK for the Go programming language.
|
||||||
|
|
||||||
The v2 SDK requires a minimum version of `Go 1.15`.
|
The v2 SDK requires a minimum version of `Go 1.15`.
|
||||||
|
|
||||||
Checkout out the [release notes](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) for information about the latest bug
|
Check out the [release notes](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) for information about the latest bug
|
||||||
fixes, updates, and features added to the SDK.
|
fixes, updates, and features added to the SDK.
|
||||||
|
|
||||||
Jump To:
|
Jump To:
|
||||||
|
|
@ -87,7 +86,7 @@ func main() {
|
||||||
###### Compile and Execute
|
###### Compile and Execute
|
||||||
```sh
|
```sh
|
||||||
$ go run .
|
$ go run .
|
||||||
Table:
|
Tables:
|
||||||
tableOne
|
tableOne
|
||||||
tableTwo
|
tableTwo
|
||||||
```
|
```
|
||||||
|
|
@ -97,9 +96,9 @@ tableTwo
|
||||||
Please use these community resources for getting help. We use the GitHub issues
|
Please use these community resources for getting help. We use the GitHub issues
|
||||||
for tracking bugs and feature requests.
|
for tracking bugs and feature requests.
|
||||||
|
|
||||||
* Ask a question on [StackOverflow](http://stackoverflow.com/) and tag it with the [`aws-sdk-go`](http://stackoverflow.com/questions/tagged/aws-sdk-go) tag.
|
* Ask us a [question](https://github.com/aws/aws-sdk-go-v2/discussions/new?category=q-a) or open a [discussion](https://github.com/aws/aws-sdk-go-v2/discussions/new?category=general).
|
||||||
* Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html).
|
|
||||||
* If you think you may have found a bug, please open an [issue](https://github.com/aws/aws-sdk-go-v2/issues/new/choose).
|
* If you think you may have found a bug, please open an [issue](https://github.com/aws/aws-sdk-go-v2/issues/new/choose).
|
||||||
|
* Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html).
|
||||||
|
|
||||||
This SDK implements AWS service APIs. For general issues regarding the AWS services and their limitations, you may also take a look at the [Amazon Web Services Discussion Forums](https://forums.aws.amazon.com/).
|
This SDK implements AWS service APIs. For general issues regarding the AWS services and their limitations, you may also take a look at the [Amazon Web Services Discussion Forums](https://forums.aws.amazon.com/).
|
||||||
|
|
||||||
|
|
@ -107,7 +106,7 @@ This SDK implements AWS service APIs. For general issues regarding the AWS servi
|
||||||
|
|
||||||
If you encounter a bug with the AWS SDK for Go we would like to hear about it.
|
If you encounter a bug with the AWS SDK for Go we would like to hear about it.
|
||||||
Search the [existing issues][Issues] and see
|
Search the [existing issues][Issues] and see
|
||||||
if others are also experiencing the issue before opening a new issue. Please
|
if others are also experiencing the same issue before opening a new issue. Please
|
||||||
include the version of AWS SDK for Go, Go language, and OS you’re using. Please
|
include the version of AWS SDK for Go, Go language, and OS you’re using. Please
|
||||||
also include reproduction case when appropriate.
|
also include reproduction case when appropriate.
|
||||||
|
|
||||||
|
|
@ -118,7 +117,7 @@ Keeping the list of open issues lean will help us respond in a timely manner.
|
||||||
|
|
||||||
## Feedback and contributing
|
## Feedback and contributing
|
||||||
|
|
||||||
The v2 SDK will use GitHub [Issues] to track feature requests and issues with the SDK. In addition, we'll use GitHub [Projects] to track large tasks spanning multiple pull requests, such as refactoring the SDK's internal request lifecycle. You can provide feedback to us in several ways.
|
The v2 SDK will use GitHub [Issues] to track feature requests and issues with the SDK. In addition, we'll use GitHub [Projects] to track large tasks spanning multiple pull requests, such as refactoring the SDK's internal request lifecycle. You can provide feedback to us in several ways.
|
||||||
|
|
||||||
**GitHub issues**. To provide feedback or report bugs, file GitHub [Issues] on the SDK. This is the preferred mechanism to give feedback so that other users can engage in the conversation, +1 issues, etc. Issues you open will be evaluated, and included in our roadmap for the GA launch.
|
**GitHub issues**. To provide feedback or report bugs, file GitHub [Issues] on the SDK. This is the preferred mechanism to give feedback so that other users can engage in the conversation, +1 issues, etc. Issues you open will be evaluated, and included in our roadmap for the GA launch.
|
||||||
|
|
||||||
|
|
@ -129,6 +128,8 @@ The v2 SDK will use GitHub [Issues] to track feature requests and issues with th
|
||||||
[SDK Developer Guide](https://aws.github.io/aws-sdk-go-v2/docs/) - Use this document to learn how to get started and
|
[SDK Developer Guide](https://aws.github.io/aws-sdk-go-v2/docs/) - Use this document to learn how to get started and
|
||||||
use the AWS SDK for Go V2.
|
use the AWS SDK for Go V2.
|
||||||
|
|
||||||
|
[SDK Migration Guide](https://aws.github.io/aws-sdk-go-v2/docs/migrating/) - Use this document to learn how to migrate to V2 from the AWS SDK for Go.
|
||||||
|
|
||||||
[SDK API Reference Documentation](https://pkg.go.dev/mod/github.com/aws/aws-sdk-go-v2) - Use this
|
[SDK API Reference Documentation](https://pkg.go.dev/mod/github.com/aws/aws-sdk-go-v2) - Use this
|
||||||
document to look up all API operation input and output parameters for AWS
|
document to look up all API operation input and output parameters for AWS
|
||||||
services supported by the SDK. The API reference also includes documentation of
|
services supported by the SDK. The API reference also includes documentation of
|
||||||
|
|
@ -137,8 +138,8 @@ API operation require parameters.
|
||||||
|
|
||||||
[Service Documentation](https://aws.amazon.com/documentation/) - Use this
|
[Service Documentation](https://aws.amazon.com/documentation/) - Use this
|
||||||
documentation to learn how to interface with AWS services. These guides are
|
documentation to learn how to interface with AWS services. These guides are
|
||||||
great for getting started with a service, or when looking for more
|
great for getting started with a service, or when looking for more
|
||||||
information about a service. While this document is not required for coding,
|
information about a service. While this document is not required for coding,
|
||||||
services may supply helpful samples to look out for.
|
services may supply helpful samples to look out for.
|
||||||
|
|
||||||
[Forum](https://forums.aws.amazon.com/forum.jspa?forumID=293) - Ask questions, get help, and give feedback
|
[Forum](https://forums.aws.amazon.com/forum.jspa?forumID=293) - Ask questions, get help, and give feedback
|
||||||
|
|
@ -149,7 +150,7 @@ services may supply helpful samples to look out for.
|
||||||
[Dep]: https://github.com/golang/dep
|
[Dep]: https://github.com/golang/dep
|
||||||
[Issues]: https://github.com/aws/aws-sdk-go-v2/issues
|
[Issues]: https://github.com/aws/aws-sdk-go-v2/issues
|
||||||
[Projects]: https://github.com/aws/aws-sdk-go-v2/projects
|
[Projects]: https://github.com/aws/aws-sdk-go-v2/projects
|
||||||
[CHANGELOG]: https://github.com/aws/aws-sdk-go-v2/blob/master/CHANGELOG.md
|
[CHANGELOG]: https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md
|
||||||
[Amazon DynamoDB]: https://aws.amazon.com/dynamodb/
|
[Amazon DynamoDB]: https://aws.amazon.com/dynamodb/
|
||||||
[design]: https://github.com/aws/aws-sdk-go-v2/blob/master/DESIGN.md
|
[design]: https://github.com/aws/aws-sdk-go-v2/blob/main/DESIGN.md
|
||||||
[license]: http://aws.amazon.com/apache2.0/
|
[license]: http://aws.amazon.com/apache2.0/
|
||||||
|
|
|
||||||
|
|
@ -75,9 +75,8 @@ func Parse(arn string) (ARN, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsARN returns whether the given string is an ARN by looking for
|
// IsARN returns whether the given string is an arn
|
||||||
// whether the string starts with "arn:" and contains the correct number
|
// by looking for whether the string starts with arn:
|
||||||
// of sections delimited by colons(:).
|
|
||||||
func IsARN(arn string) bool {
|
func IsARN(arn string) bool {
|
||||||
return strings.HasPrefix(arn, arnPrefix) && strings.Count(arn, ":") >= arnSections-1
|
return strings.HasPrefix(arn, arnPrefix) && strings.Count(arn, ":") >= arnSections-1
|
||||||
}
|
}
|
||||||
|
|
@ -3,13 +3,14 @@ package aws
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
smithybearer "github.com/aws/smithy-go/auth/bearer"
|
||||||
"github.com/aws/smithy-go/logging"
|
"github.com/aws/smithy-go/logging"
|
||||||
"github.com/aws/smithy-go/middleware"
|
"github.com/aws/smithy-go/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTTPClient provides the interface to provide custom HTTPClients. Generally
|
// HTTPClient provides the interface to provide custom HTTPClients. Generally
|
||||||
// *http.Client is sufficient for most use cases. The HTTPClient should not
|
// *http.Client is sufficient for most use cases. The HTTPClient should not
|
||||||
// follow redirects.
|
// follow 301 or 302 redirects.
|
||||||
type HTTPClient interface {
|
type HTTPClient interface {
|
||||||
Do(*http.Request) (*http.Response, error)
|
Do(*http.Request) (*http.Response, error)
|
||||||
}
|
}
|
||||||
|
|
@ -25,11 +26,23 @@ type Config struct {
|
||||||
// information on AWS regions.
|
// information on AWS regions.
|
||||||
Region string
|
Region string
|
||||||
|
|
||||||
// The credentials object to use when signing requests. Defaults to a
|
// The credentials object to use when signing requests.
|
||||||
// chain of credential providers to search for credentials in environment
|
// Use the LoadDefaultConfig to load configuration from all the SDK's supported
|
||||||
// variables, shared credential file, and EC2 Instance Roles.
|
// sources, and resolve credentials using the SDK's default credential chain.
|
||||||
Credentials CredentialsProvider
|
Credentials CredentialsProvider
|
||||||
|
|
||||||
|
// The Bearer Authentication token provider to use for authenticating API
|
||||||
|
// operation calls with a Bearer Authentication token. The API clients and
|
||||||
|
// operation must support Bearer Authentication scheme in order for the
|
||||||
|
// token provider to be used. API clients created with NewFromConfig will
|
||||||
|
// automatically be configured with this option, if the API client support
|
||||||
|
// Bearer Authentication.
|
||||||
|
//
|
||||||
|
// The SDK's config.LoadDefaultConfig can automatically populate this
|
||||||
|
// option for external configuration options such as SSO session.
|
||||||
|
// https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html
|
||||||
|
BearerAuthTokenProvider smithybearer.TokenProvider
|
||||||
|
|
||||||
// The HTTP Client the SDK's API clients will use to invoke HTTP requests.
|
// The HTTP Client the SDK's API clients will use to invoke HTTP requests.
|
||||||
// The SDK defaults to a BuildableClient allowing API clients to create
|
// The SDK defaults to a BuildableClient allowing API clients to create
|
||||||
// copies of the HTTP Client for service specific customizations.
|
// copies of the HTTP Client for service specific customizations.
|
||||||
|
|
|
||||||
|
|
@ -46,14 +46,14 @@ type CredentialsCacheOptions struct {
|
||||||
// CredentialsCache will look for optional interfaces on the Provider to adjust
|
// CredentialsCache will look for optional interfaces on the Provider to adjust
|
||||||
// how the credential cache handles credentials caching.
|
// how the credential cache handles credentials caching.
|
||||||
//
|
//
|
||||||
// * HandleFailRefreshCredentialsCacheStrategy - Allows provider to handle
|
// - HandleFailRefreshCredentialsCacheStrategy - Allows provider to handle
|
||||||
// credential refresh failures. This could return an updated Credentials
|
// credential refresh failures. This could return an updated Credentials
|
||||||
// value, or attempt another means of retrieving credentials.
|
// value, or attempt another means of retrieving credentials.
|
||||||
//
|
//
|
||||||
// * AdjustExpiresByCredentialsCacheStrategy - Allows provider to adjust how
|
// - AdjustExpiresByCredentialsCacheStrategy - Allows provider to adjust how
|
||||||
// credentials Expires is modified. This could modify how the Credentials
|
// credentials Expires is modified. This could modify how the Credentials
|
||||||
// Expires is adjusted based on the CredentialsCache ExpiryWindow option.
|
// Expires is adjusted based on the CredentialsCache ExpiryWindow option.
|
||||||
// Such as providing a floor not to reduce the Expires below.
|
// Such as providing a floor not to reduce the Expires below.
|
||||||
type CredentialsCache struct {
|
type CredentialsCache struct {
|
||||||
provider CredentialsProvider
|
provider CredentialsProvider
|
||||||
|
|
||||||
|
|
@ -178,6 +178,12 @@ func (p *CredentialsCache) Invalidate() {
|
||||||
p.creds.Store((*Credentials)(nil))
|
p.creds.Store((*Credentials)(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsCredentialsProvider returns whether credential provider wrapped by CredentialsCache
|
||||||
|
// matches the target provider type.
|
||||||
|
func (p *CredentialsCache) IsCredentialsProvider(target CredentialsProvider) bool {
|
||||||
|
return IsCredentialsProvider(p.provider, target)
|
||||||
|
}
|
||||||
|
|
||||||
// HandleFailRefreshCredentialsCacheStrategy is an interface for
|
// HandleFailRefreshCredentialsCacheStrategy is an interface for
|
||||||
// CredentialsCache to allow CredentialsProvider how failed to refresh
|
// CredentialsCache to allow CredentialsProvider how failed to refresh
|
||||||
// credentials is handled.
|
// credentials is handled.
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package aws
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||||
|
|
@ -23,41 +24,41 @@ import (
|
||||||
// The following example demonstrates using the AnonymousCredentials to prevent
|
// The following example demonstrates using the AnonymousCredentials to prevent
|
||||||
// SDK's external config loading attempt to resolve credentials.
|
// SDK's external config loading attempt to resolve credentials.
|
||||||
//
|
//
|
||||||
// cfg, err := config.LoadDefaultConfig(context.TODO(),
|
// cfg, err := config.LoadDefaultConfig(context.TODO(),
|
||||||
// config.WithCredentialsProvider(aws.AnonymousCredentials{}),
|
// config.WithCredentialsProvider(aws.AnonymousCredentials{}),
|
||||||
// )
|
// )
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// log.Fatalf("failed to load config, %v", err)
|
// log.Fatalf("failed to load config, %v", err)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// client := s3.NewFromConfig(cfg)
|
// client := s3.NewFromConfig(cfg)
|
||||||
//
|
//
|
||||||
// Alternatively you can leave the API client Option's `Credential` member to
|
// Alternatively you can leave the API client Option's `Credential` member to
|
||||||
// nil. If using the `NewFromConfig` constructor you'll need to explicitly set
|
// nil. If using the `NewFromConfig` constructor you'll need to explicitly set
|
||||||
// the `Credentials` member to nil, if the external config resolved a
|
// the `Credentials` member to nil, if the external config resolved a
|
||||||
// credential provider.
|
// credential provider.
|
||||||
//
|
//
|
||||||
// client := s3.New(s3.Options{
|
// client := s3.New(s3.Options{
|
||||||
// // Credentials defaults to a nil value.
|
// // Credentials defaults to a nil value.
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// This can also be configured for specific operations calls too.
|
// This can also be configured for specific operations calls too.
|
||||||
//
|
//
|
||||||
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// log.Fatalf("failed to load config, %v", err)
|
// log.Fatalf("failed to load config, %v", err)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// client := s3.NewFromConfig(config)
|
// client := s3.NewFromConfig(config)
|
||||||
//
|
//
|
||||||
// result, err := client.GetObject(context.TODO(), s3.GetObject{
|
// result, err := client.GetObject(context.TODO(), s3.GetObject{
|
||||||
// Bucket: aws.String("example-bucket"),
|
// Bucket: aws.String("example-bucket"),
|
||||||
// Key: aws.String("example-key"),
|
// Key: aws.String("example-key"),
|
||||||
// }, func(o *s3.Options) {
|
// }, func(o *s3.Options) {
|
||||||
// o.Credentials = nil
|
// o.Credentials = nil
|
||||||
// // Or
|
// // Or
|
||||||
// o.Credentials = aws.AnonymousCredentials{}
|
// o.Credentials = aws.AnonymousCredentials{}
|
||||||
// })
|
// })
|
||||||
type AnonymousCredentials struct{}
|
type AnonymousCredentials struct{}
|
||||||
|
|
||||||
// Retrieve implements the CredentialsProvider interface, but will always
|
// Retrieve implements the CredentialsProvider interface, but will always
|
||||||
|
|
@ -129,3 +130,41 @@ type CredentialsProviderFunc func(context.Context) (Credentials, error)
|
||||||
func (fn CredentialsProviderFunc) Retrieve(ctx context.Context) (Credentials, error) {
|
func (fn CredentialsProviderFunc) Retrieve(ctx context.Context) (Credentials, error) {
|
||||||
return fn(ctx)
|
return fn(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type isCredentialsProvider interface {
|
||||||
|
IsCredentialsProvider(CredentialsProvider) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCredentialsProvider returns whether the target CredentialProvider is the same type as provider when comparing the
|
||||||
|
// implementation type.
|
||||||
|
//
|
||||||
|
// If provider has a method IsCredentialsProvider(CredentialsProvider) bool it will be responsible for validating
|
||||||
|
// whether target matches the credential provider type.
|
||||||
|
//
|
||||||
|
// When comparing the CredentialProvider implementations provider and target for equality, the following rules are used:
|
||||||
|
//
|
||||||
|
// If provider is of type T and target is of type V, true if type *T is the same as type *V, otherwise false
|
||||||
|
// If provider is of type *T and target is of type V, true if type *T is the same as type *V, otherwise false
|
||||||
|
// If provider is of type T and target is of type *V, true if type *T is the same as type *V, otherwise false
|
||||||
|
// If provider is of type *T and target is of type *V,true if type *T is the same as type *V, otherwise false
|
||||||
|
func IsCredentialsProvider(provider, target CredentialsProvider) bool {
|
||||||
|
if target == nil || provider == nil {
|
||||||
|
return provider == target
|
||||||
|
}
|
||||||
|
|
||||||
|
if x, ok := provider.(isCredentialsProvider); ok {
|
||||||
|
return x.IsCredentialsProvider(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
targetType := reflect.TypeOf(target)
|
||||||
|
if targetType.Kind() != reflect.Ptr {
|
||||||
|
targetType = reflect.PtrTo(targetType)
|
||||||
|
}
|
||||||
|
|
||||||
|
providerType := reflect.TypeOf(provider)
|
||||||
|
if providerType.Kind() != reflect.Ptr {
|
||||||
|
providerType = reflect.PtrTo(providerType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetType.AssignableTo(providerType)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Package aws provides the core SDK's utilities and shared types. Use this package's
|
// Package aws provides the core SDK's utilities and shared types. Use this package's
|
||||||
// utilities to simplify setting and reading API operations parameters.
|
// utilities to simplify setting and reading API operations parameters.
|
||||||
//
|
//
|
||||||
// Value and Pointer Conversion Utilities
|
// # Value and Pointer Conversion Utilities
|
||||||
//
|
//
|
||||||
// This package includes a helper conversion utility for each scalar type the SDK's
|
// This package includes a helper conversion utility for each scalar type the SDK's
|
||||||
// API use. These utilities make getting a pointer of the scalar, and dereferencing
|
// API use. These utilities make getting a pointer of the scalar, and dereferencing
|
||||||
|
|
@ -16,33 +16,33 @@
|
||||||
// to get pointer of a literal string value, because getting the address of a
|
// to get pointer of a literal string value, because getting the address of a
|
||||||
// literal requires assigning the value to a variable first.
|
// literal requires assigning the value to a variable first.
|
||||||
//
|
//
|
||||||
// var strPtr *string
|
// var strPtr *string
|
||||||
//
|
//
|
||||||
// // Without the SDK's conversion functions
|
// // Without the SDK's conversion functions
|
||||||
// str := "my string"
|
// str := "my string"
|
||||||
// strPtr = &str
|
// strPtr = &str
|
||||||
//
|
//
|
||||||
// // With the SDK's conversion functions
|
// // With the SDK's conversion functions
|
||||||
// strPtr = aws.String("my string")
|
// strPtr = aws.String("my string")
|
||||||
//
|
//
|
||||||
// // Convert *string to string value
|
// // Convert *string to string value
|
||||||
// str = aws.ToString(strPtr)
|
// str = aws.ToString(strPtr)
|
||||||
//
|
//
|
||||||
// In addition to scalars the aws package also includes conversion utilities for
|
// In addition to scalars the aws package also includes conversion utilities for
|
||||||
// map and slice for commonly types used in API parameters. The map and slice
|
// map and slice for commonly types used in API parameters. The map and slice
|
||||||
// conversion functions use similar naming pattern as the scalar conversion
|
// conversion functions use similar naming pattern as the scalar conversion
|
||||||
// functions.
|
// functions.
|
||||||
//
|
//
|
||||||
// var strPtrs []*string
|
// var strPtrs []*string
|
||||||
// var strs []string = []string{"Go", "Gophers", "Go"}
|
// var strs []string = []string{"Go", "Gophers", "Go"}
|
||||||
//
|
//
|
||||||
// // Convert []string to []*string
|
// // Convert []string to []*string
|
||||||
// strPtrs = aws.StringSlice(strs)
|
// strPtrs = aws.StringSlice(strs)
|
||||||
//
|
//
|
||||||
// // Convert []*string to []string
|
// // Convert []*string to []string
|
||||||
// strs = aws.ToStringSlice(strPtrs)
|
// strs = aws.ToStringSlice(strPtrs)
|
||||||
//
|
//
|
||||||
// SDK Default HTTP Client
|
// # SDK Default HTTP Client
|
||||||
//
|
//
|
||||||
// The SDK will use the http.DefaultClient if a HTTP client is not provided to
|
// The SDK will use the http.DefaultClient if a HTTP client is not provided to
|
||||||
// the SDK's Session, or service client constructor. This means that if the
|
// the SDK's Session, or service client constructor. This means that if the
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,4 @@
|
||||||
package aws
|
package aws
|
||||||
|
|
||||||
// goModuleVersion is the tagged release for this module
|
// goModuleVersion is the tagged release for this module
|
||||||
const goModuleVersion = "1.16.3"
|
const goModuleVersion = "1.18.0"
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,12 @@ package aws
|
||||||
// The entire 64-bit group is reserved for later expansion by the SDK.
|
// The entire 64-bit group is reserved for later expansion by the SDK.
|
||||||
//
|
//
|
||||||
// Example: Setting ClientLogMode to enable logging of retries and requests
|
// Example: Setting ClientLogMode to enable logging of retries and requests
|
||||||
// clientLogMode := aws.LogRetries | aws.LogRequest
|
//
|
||||||
|
// clientLogMode := aws.LogRetries | aws.LogRequest
|
||||||
//
|
//
|
||||||
// Example: Adding an additional log mode to an existing ClientLogMode value
|
// Example: Adding an additional log mode to an existing ClientLogMode value
|
||||||
// clientLogMode |= aws.LogResponse
|
//
|
||||||
|
// clientLogMode |= aws.LogResponse
|
||||||
type ClientLogMode uint64
|
type ClientLogMode uint64
|
||||||
|
|
||||||
// Supported ClientLogMode bits that can be configured to toggle logging of specific SDK events.
|
// Supported ClientLogMode bits that can be configured to toggle logging of specific SDK events.
|
||||||
|
|
|
||||||
94
vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/recursion_detection.go
generated
vendored
Normal file
94
vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/recursion_detection.go
generated
vendored
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/aws/smithy-go/middleware"
|
||||||
|
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const envAwsLambdaFunctionName = "AWS_LAMBDA_FUNCTION_NAME"
|
||||||
|
const envAmznTraceID = "_X_AMZN_TRACE_ID"
|
||||||
|
const amznTraceIDHeader = "X-Amzn-Trace-Id"
|
||||||
|
|
||||||
|
// AddRecursionDetection adds recursionDetection to the middleware stack
|
||||||
|
func AddRecursionDetection(stack *middleware.Stack) error {
|
||||||
|
return stack.Build.Add(&RecursionDetection{}, middleware.After)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecursionDetection detects Lambda environment and sets its X-Ray trace ID to request header if absent
|
||||||
|
// to avoid recursion invocation in Lambda
|
||||||
|
type RecursionDetection struct{}
|
||||||
|
|
||||||
|
// ID returns the middleware identifier
|
||||||
|
func (m *RecursionDetection) ID() string {
|
||||||
|
return "RecursionDetection"
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleBuild detects Lambda environment and adds its trace ID to request header if absent
|
||||||
|
func (m *RecursionDetection) HandleBuild(
|
||||||
|
ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler,
|
||||||
|
) (
|
||||||
|
out middleware.BuildOutput, metadata middleware.Metadata, err error,
|
||||||
|
) {
|
||||||
|
req, ok := in.Request.(*smithyhttp.Request)
|
||||||
|
if !ok {
|
||||||
|
return out, metadata, fmt.Errorf("unknown request type %T", req)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, hasLambdaEnv := os.LookupEnv(envAwsLambdaFunctionName)
|
||||||
|
xAmznTraceID, hasTraceID := os.LookupEnv(envAmznTraceID)
|
||||||
|
value := req.Header.Get(amznTraceIDHeader)
|
||||||
|
// only set the X-Amzn-Trace-Id header when it is not set initially, the
|
||||||
|
// current environment is Lambda and the _X_AMZN_TRACE_ID env variable exists
|
||||||
|
if value != "" || !hasLambdaEnv || !hasTraceID {
|
||||||
|
return next.HandleBuild(ctx, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set(amznTraceIDHeader, percentEncode(xAmznTraceID))
|
||||||
|
return next.HandleBuild(ctx, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
func percentEncode(s string) string {
|
||||||
|
upperhex := "0123456789ABCDEF"
|
||||||
|
hexCount := 0
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
c := s[i]
|
||||||
|
if shouldEncode(c) {
|
||||||
|
hexCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hexCount == 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
required := len(s) + 2*hexCount
|
||||||
|
t := make([]byte, required)
|
||||||
|
j := 0
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if c := s[i]; shouldEncode(c) {
|
||||||
|
t[j] = '%'
|
||||||
|
t[j+1] = upperhex[c>>4]
|
||||||
|
t[j+2] = upperhex[c&15]
|
||||||
|
j += 3
|
||||||
|
} else {
|
||||||
|
t[j] = c
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldEncode(c byte) bool {
|
||||||
|
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case '-', '=', ';', ':', '+', '&', '[', ']', '{', '}', '"', '\'', ',':
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -68,10 +68,12 @@ type requestUserAgent struct {
|
||||||
// request.
|
// request.
|
||||||
//
|
//
|
||||||
// User-Agent example:
|
// User-Agent example:
|
||||||
// aws-sdk-go-v2/1.2.3
|
//
|
||||||
|
// aws-sdk-go-v2/1.2.3
|
||||||
//
|
//
|
||||||
// X-Amz-User-Agent example:
|
// X-Amz-User-Agent example:
|
||||||
// aws-sdk-go-v2/1.2.3 md/GOOS/linux md/GOARCH/amd64 lang/go/1.15
|
//
|
||||||
|
// aws-sdk-go-v2/1.2.3 md/GOOS/linux md/GOARCH/amd64 lang/go/1.15
|
||||||
func newRequestUserAgent() *requestUserAgent {
|
func newRequestUserAgent() *requestUserAgent {
|
||||||
userAgent, sdkAgent := smithyhttp.NewUserAgentBuilder(), smithyhttp.NewUserAgentBuilder()
|
userAgent, sdkAgent := smithyhttp.NewUserAgentBuilder(), smithyhttp.NewUserAgentBuilder()
|
||||||
addProductName(userAgent)
|
addProductName(userAgent)
|
||||||
|
|
|
||||||
62
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md
generated
vendored
Normal file
62
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
# v1.4.10 (2022-12-02)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.4.9 (2022-10-24)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.4.8 (2022-09-14)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.4.7 (2022-09-02)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.4.6 (2022-08-31)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.4.5 (2022-08-29)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.4.4 (2022-08-09)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.4.3 (2022-06-29)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.4.2 (2022-06-07)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.4.1 (2022-03-24)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.4.0 (2022-03-08)
|
||||||
|
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
|
||||||
|
# v1.3.0 (2022-02-24)
|
||||||
|
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
|
||||||
|
# v1.2.0 (2022-01-14)
|
||||||
|
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
|
||||||
|
# v1.1.0 (2022-01-07)
|
||||||
|
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
|
||||||
|
# v1.0.0 (2021-11-06)
|
||||||
|
|
||||||
|
* **Announcement**: Support has been added for AWS EventStream APIs for Kinesis, S3, and Transcribe Streaming. Support for the Lex Runtime V2 EventStream API will be added in a future release.
|
||||||
|
* **Release**: Protocol support has been added for AWS event stream.
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
|
||||||
|
|
@ -6,63 +6,62 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/aws/smithy-go/logging"
|
||||||
"hash"
|
"hash"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DecoderOptions is the Decoder configuration options.
|
||||||
|
type DecoderOptions struct {
|
||||||
|
Logger logging.Logger
|
||||||
|
LogMessages bool
|
||||||
|
}
|
||||||
|
|
||||||
// Decoder provides decoding of an Event Stream messages.
|
// Decoder provides decoding of an Event Stream messages.
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
r io.Reader
|
options DecoderOptions
|
||||||
logger aws.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDecoder initializes and returns a Decoder for decoding event
|
// NewDecoder initializes and returns a Decoder for decoding event
|
||||||
// stream messages from the reader provided.
|
// stream messages from the reader provided.
|
||||||
func NewDecoder(r io.Reader, opts ...func(*Decoder)) *Decoder {
|
func NewDecoder(optFns ...func(*DecoderOptions)) *Decoder {
|
||||||
d := &Decoder{
|
options := DecoderOptions{}
|
||||||
r: r,
|
|
||||||
|
for _, fn := range optFns {
|
||||||
|
fn(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, opt := range opts {
|
return &Decoder{
|
||||||
opt(d)
|
options: options,
|
||||||
}
|
|
||||||
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeWithLogger adds a logger to be used by the decoder when decoding
|
|
||||||
// stream events.
|
|
||||||
func DecodeWithLogger(logger aws.Logger) func(*Decoder) {
|
|
||||||
return func(d *Decoder) {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode attempts to decode a single message from the event stream reader.
|
// Decode attempts to decode a single message from the event stream reader.
|
||||||
// Will return the event stream message, or error if Decode fails to read
|
// Will return the event stream message, or error if decodeMessage fails to read
|
||||||
// the message from the stream.
|
// the message from the stream.
|
||||||
func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) {
|
//
|
||||||
reader := d.r
|
// payloadBuf is a byte slice that will be used in the returned Message.Payload. Callers
|
||||||
if d.logger != nil {
|
// must ensure that the Message.Payload from a previous decode has been consumed before passing in the same underlying
|
||||||
|
// payloadBuf byte slice.
|
||||||
|
func (d *Decoder) Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) {
|
||||||
|
if d.options.Logger != nil && d.options.LogMessages {
|
||||||
debugMsgBuf := bytes.NewBuffer(nil)
|
debugMsgBuf := bytes.NewBuffer(nil)
|
||||||
reader = io.TeeReader(reader, debugMsgBuf)
|
reader = io.TeeReader(reader, debugMsgBuf)
|
||||||
defer func() {
|
defer func() {
|
||||||
logMessageDecode(d.logger, debugMsgBuf, m, err)
|
logMessageDecode(d.options.Logger, debugMsgBuf, m, err)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err = Decode(reader, payloadBuf)
|
m, err = decodeMessage(reader, payloadBuf)
|
||||||
|
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode attempts to decode a single message from the event stream reader.
|
// decodeMessage attempts to decode a single message from the event stream reader.
|
||||||
// Will return the event stream message, or error if Decode fails to read
|
// Will return the event stream message, or error if decodeMessage fails to read
|
||||||
// the message from the reader.
|
// the message from the reader.
|
||||||
func Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) {
|
func decodeMessage(reader io.Reader, payloadBuf []byte) (m Message, err error) {
|
||||||
crc := crc32.New(crc32IEEETable)
|
crc := crc32.New(crc32IEEETable)
|
||||||
hashReader := io.TeeReader(reader, crc)
|
hashReader := io.TeeReader(reader, crc)
|
||||||
|
|
||||||
|
|
@ -95,15 +94,15 @@ func Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func logMessageDecode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
|
func logMessageDecode(logger logging.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
|
||||||
w := bytes.NewBuffer(nil)
|
w := bytes.NewBuffer(nil)
|
||||||
defer func() { logger.Log(w.String()) }()
|
defer func() { logger.Logf(logging.Debug, w.String()) }()
|
||||||
|
|
||||||
fmt.Fprintf(w, "Raw message:\n%s\n",
|
fmt.Fprintf(w, "Raw message:\n%s\n",
|
||||||
hex.Dump(msgBuf.Bytes()))
|
hex.Dump(msgBuf.Bytes()))
|
||||||
|
|
||||||
if decodeErr != nil {
|
if decodeErr != nil {
|
||||||
fmt.Fprintf(w, "Decode error: %v\n", decodeErr)
|
fmt.Fprintf(w, "decodeMessage error: %v\n", decodeErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,13 +166,14 @@ func decodeUint8(r io.Reader) (uint8, error) {
|
||||||
|
|
||||||
if br, ok := r.(byteReader); ok {
|
if br, ok := r.(byteReader); ok {
|
||||||
v, err := br.ReadByte()
|
v, err := br.ReadByte()
|
||||||
return uint8(v), err
|
return v, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var b [1]byte
|
var b [1]byte
|
||||||
_, err := io.ReadFull(r, b[:])
|
_, err := io.ReadFull(r, b[:])
|
||||||
return uint8(b[0]), err
|
return b[0], err
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeUint16(r io.Reader) (uint16, error) {
|
func decodeUint16(r io.Reader) (uint16, error) {
|
||||||
var b [2]byte
|
var b [2]byte
|
||||||
bs := b[:]
|
bs := b[:]
|
||||||
|
|
@ -183,6 +183,7 @@ func decodeUint16(r io.Reader) (uint16, error) {
|
||||||
}
|
}
|
||||||
return binary.BigEndian.Uint16(bs), nil
|
return binary.BigEndian.Uint16(bs), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeUint32(r io.Reader) (uint32, error) {
|
func decodeUint32(r io.Reader) (uint32, error) {
|
||||||
var b [4]byte
|
var b [4]byte
|
||||||
bs := b[:]
|
bs := b[:]
|
||||||
|
|
@ -192,6 +193,7 @@ func decodeUint32(r io.Reader) (uint32, error) {
|
||||||
}
|
}
|
||||||
return binary.BigEndian.Uint32(bs), nil
|
return binary.BigEndian.Uint32(bs), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeUint64(r io.Reader) (uint64, error) {
|
func decodeUint64(r io.Reader) (uint64, error) {
|
||||||
var b [8]byte
|
var b [8]byte
|
||||||
bs := b[:]
|
bs := b[:]
|
||||||
|
|
@ -6,55 +6,54 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/aws/smithy-go/logging"
|
||||||
"hash"
|
"hash"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EncoderOptions is the configuration options for Encoder.
|
||||||
|
type EncoderOptions struct {
|
||||||
|
Logger logging.Logger
|
||||||
|
LogMessages bool
|
||||||
|
}
|
||||||
|
|
||||||
// Encoder provides EventStream message encoding.
|
// Encoder provides EventStream message encoding.
|
||||||
type Encoder struct {
|
type Encoder struct {
|
||||||
w io.Writer
|
options EncoderOptions
|
||||||
logger aws.Logger
|
|
||||||
|
|
||||||
headersBuf *bytes.Buffer
|
headersBuf *bytes.Buffer
|
||||||
|
messageBuf *bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEncoder initializes and returns an Encoder to encode Event Stream
|
// NewEncoder initializes and returns an Encoder to encode Event Stream
|
||||||
// messages to an io.Writer.
|
// messages.
|
||||||
func NewEncoder(w io.Writer, opts ...func(*Encoder)) *Encoder {
|
func NewEncoder(optFns ...func(*EncoderOptions)) *Encoder {
|
||||||
e := &Encoder{
|
o := EncoderOptions{}
|
||||||
w: w,
|
|
||||||
|
for _, fn := range optFns {
|
||||||
|
fn(&o)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Encoder{
|
||||||
|
options: o,
|
||||||
headersBuf: bytes.NewBuffer(nil),
|
headersBuf: bytes.NewBuffer(nil),
|
||||||
}
|
messageBuf: bytes.NewBuffer(nil),
|
||||||
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeWithLogger adds a logger to be used by the encode when decoding
|
|
||||||
// stream events.
|
|
||||||
func EncodeWithLogger(logger aws.Logger) func(*Encoder) {
|
|
||||||
return func(d *Encoder) {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode encodes a single EventStream message to the io.Writer the Encoder
|
// Encode encodes a single EventStream message to the io.Writer the Encoder
|
||||||
// was created with. An error is returned if writing the message fails.
|
// was created with. An error is returned if writing the message fails.
|
||||||
func (e *Encoder) Encode(msg Message) (err error) {
|
func (e *Encoder) Encode(w io.Writer, msg Message) (err error) {
|
||||||
e.headersBuf.Reset()
|
e.headersBuf.Reset()
|
||||||
|
e.messageBuf.Reset()
|
||||||
|
|
||||||
writer := e.w
|
var writer io.Writer = e.messageBuf
|
||||||
if e.logger != nil {
|
if e.options.Logger != nil && e.options.LogMessages {
|
||||||
encodeMsgBuf := bytes.NewBuffer(nil)
|
encodeMsgBuf := bytes.NewBuffer(nil)
|
||||||
writer = io.MultiWriter(writer, encodeMsgBuf)
|
writer = io.MultiWriter(writer, encodeMsgBuf)
|
||||||
defer func() {
|
defer func() {
|
||||||
logMessageEncode(e.logger, encodeMsgBuf, msg, err)
|
logMessageEncode(e.options.Logger, encodeMsgBuf, msg, err)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,12 +84,18 @@ func (e *Encoder) Encode(msg Message) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
msgCRC := crc.Sum32()
|
msgCRC := crc.Sum32()
|
||||||
return binary.Write(writer, binary.BigEndian, msgCRC)
|
if err := binary.Write(writer, binary.BigEndian, msgCRC); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(w, e.messageBuf)
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func logMessageEncode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, encodeErr error) {
|
func logMessageEncode(logger logging.Logger, msgBuf *bytes.Buffer, msg Message, encodeErr error) {
|
||||||
w := bytes.NewBuffer(nil)
|
w := bytes.NewBuffer(nil)
|
||||||
defer func() { logger.Log(w.String()) }()
|
defer func() { logger.Logf(logging.Debug, w.String()) }()
|
||||||
|
|
||||||
fmt.Fprintf(w, "Message to encode:\n")
|
fmt.Fprintf(w, "Message to encode:\n")
|
||||||
encoder := json.NewEncoder(w)
|
encoder := json.NewEncoder(w)
|
||||||
|
|
@ -4,6 +4,7 @@ package eventstreamapi
|
||||||
const (
|
const (
|
||||||
ChunkSignatureHeader = `:chunk-signature` // chunk signature for message
|
ChunkSignatureHeader = `:chunk-signature` // chunk signature for message
|
||||||
DateHeader = `:date` // Date header for signature
|
DateHeader = `:date` // Date header for signature
|
||||||
|
ContentTypeHeader = ":content-type" // message payload content-type
|
||||||
|
|
||||||
// Message header and values
|
// Message header and values
|
||||||
MessageTypeHeader = `:message-type` // Identifies type of message.
|
MessageTypeHeader = `:message-type` // Identifies type of message.
|
||||||
71
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/middleware.go
generated
vendored
Normal file
71
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/middleware.go
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
package eventstreamapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/aws/smithy-go/middleware"
|
||||||
|
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventStreamWriterKey struct{}
|
||||||
|
|
||||||
|
// GetInputStreamWriter returns EventTypeHeader io.PipeWriter used for the operation's input event stream.
|
||||||
|
func GetInputStreamWriter(ctx context.Context) io.WriteCloser {
|
||||||
|
writeCloser, _ := middleware.GetStackValue(ctx, eventStreamWriterKey{}).(io.WriteCloser)
|
||||||
|
return writeCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
func setInputStreamWriter(ctx context.Context, writeCloser io.WriteCloser) context.Context {
|
||||||
|
return middleware.WithStackValue(ctx, eventStreamWriterKey{}, writeCloser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeStreamWriter is a Finalize middleware initializes an in-memory pipe for sending event stream messages
|
||||||
|
// via the HTTP request body.
|
||||||
|
type InitializeStreamWriter struct{}
|
||||||
|
|
||||||
|
// AddInitializeStreamWriter adds the InitializeStreamWriter middleware to the provided stack.
|
||||||
|
func AddInitializeStreamWriter(stack *middleware.Stack) error {
|
||||||
|
return stack.Finalize.Add(&InitializeStreamWriter{}, middleware.After)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the identifier for the middleware.
|
||||||
|
func (i *InitializeStreamWriter) ID() string {
|
||||||
|
return "InitializeStreamWriter"
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleFinalize is the middleware implementation.
|
||||||
|
func (i *InitializeStreamWriter) HandleFinalize(
|
||||||
|
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
|
||||||
|
) (
|
||||||
|
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||||
|
) {
|
||||||
|
request, ok := in.Request.(*smithyhttp.Request)
|
||||||
|
if !ok {
|
||||||
|
return out, metadata, fmt.Errorf("unknown transport type: %T", in.Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputReader, inputWriter := io.Pipe()
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = inputReader.Close()
|
||||||
|
_ = inputWriter.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
request, err = request.SetStream(inputReader)
|
||||||
|
if err != nil {
|
||||||
|
return out, metadata, err
|
||||||
|
}
|
||||||
|
in.Request = request
|
||||||
|
|
||||||
|
ctx = setInputStreamWriter(ctx, inputWriter)
|
||||||
|
|
||||||
|
out, metadata, err = next.HandleFinalize(ctx, in)
|
||||||
|
if err != nil {
|
||||||
|
return out, metadata, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, metadata, err
|
||||||
|
}
|
||||||
13
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/transport.go
generated
vendored
Normal file
13
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/transport.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
|
package eventstreamapi
|
||||||
|
|
||||||
|
import smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||||
|
|
||||||
|
// ApplyHTTPTransportFixes applies fixes to the HTTP request for proper event stream functionality.
|
||||||
|
//
|
||||||
|
// This operation is a no-op for Go 1.18 and above.
|
||||||
|
func ApplyHTTPTransportFixes(r *smithyhttp.Request) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
12
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/transport_go117.go
generated
vendored
Normal file
12
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/transport_go117.go
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
//go:build !go1.18
|
||||||
|
// +build !go1.18
|
||||||
|
|
||||||
|
package eventstreamapi
|
||||||
|
|
||||||
|
import smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||||
|
|
||||||
|
// ApplyHTTPTransportFixes applies fixes to the HTTP request for proper event stream functionality.
|
||||||
|
func ApplyHTTPTransportFixes(r *smithyhttp.Request) error {
|
||||||
|
r.Header.Set("Expect", "100-continue")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
6
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go
generated
vendored
Normal file
6
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Code generated by internal/repotools/cmd/updatemodulemeta DO NOT EDIT.
|
||||||
|
|
||||||
|
package eventstream
|
||||||
|
|
||||||
|
// goModuleVersion is the tagged release for this module
|
||||||
|
const goModuleVersion = "1.4.10"
|
||||||
|
|
@ -3,6 +3,7 @@ package eventstream
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -487,7 +488,21 @@ func (UUIDValue) valueType() valueType {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v UUIDValue) String() string {
|
func (v UUIDValue) String() string {
|
||||||
return fmt.Sprintf(`%X-%X-%X-%X-%X`, v[0:4], v[4:6], v[6:8], v[8:10], v[10:])
|
var scratch [36]byte
|
||||||
|
|
||||||
|
const dash = '-'
|
||||||
|
|
||||||
|
hex.Encode(scratch[:8], v[0:4])
|
||||||
|
scratch[8] = dash
|
||||||
|
hex.Encode(scratch[9:13], v[4:6])
|
||||||
|
scratch[13] = dash
|
||||||
|
hex.Encode(scratch[14:18], v[6:8])
|
||||||
|
scratch[18] = dash
|
||||||
|
hex.Encode(scratch[19:23], v[8:10])
|
||||||
|
scratch[23] = dash
|
||||||
|
hex.Encode(scratch[24:], v[10:])
|
||||||
|
|
||||||
|
return string(scratch[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode encodes the UUIDValue into an eventstream binary value
|
// encode encodes the UUIDValue into an eventstream binary value
|
||||||
|
|
@ -9,9 +9,9 @@ import (
|
||||||
// representation of a list of values of a fixed type. A serialized array might
|
// representation of a list of values of a fixed type. A serialized array might
|
||||||
// look like the following:
|
// look like the following:
|
||||||
//
|
//
|
||||||
// ListName.member.1=foo
|
// ListName.member.1=foo
|
||||||
// &ListName.member.2=bar
|
// &ListName.member.2=bar
|
||||||
// &Listname.member.3=baz
|
// &Listname.member.3=baz
|
||||||
type Array struct {
|
type Array struct {
|
||||||
// The query values to add the array to.
|
// The query values to add the array to.
|
||||||
values url.Values
|
values url.Values
|
||||||
|
|
@ -36,20 +36,31 @@ type Array struct {
|
||||||
memberName string
|
memberName string
|
||||||
// Elements are stored in values, so we keep track of the list size here.
|
// Elements are stored in values, so we keep track of the list size here.
|
||||||
size int32
|
size int32
|
||||||
|
// Empty lists are encoded as "<prefix>=", if we add a value later we will
|
||||||
|
// remove this encoding
|
||||||
|
emptyValue Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArray(values url.Values, prefix string, flat bool, memberName string) *Array {
|
func newArray(values url.Values, prefix string, flat bool, memberName string) *Array {
|
||||||
|
emptyValue := newValue(values, prefix, flat)
|
||||||
|
emptyValue.String("")
|
||||||
|
|
||||||
return &Array{
|
return &Array{
|
||||||
values: values,
|
values: values,
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
flat: flat,
|
flat: flat,
|
||||||
memberName: memberName,
|
memberName: memberName,
|
||||||
|
emptyValue: emptyValue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value adds a new element to the Query Array. Returns a Value type used to
|
// Value adds a new element to the Query Array. Returns a Value type used to
|
||||||
// encode the array element.
|
// encode the array element.
|
||||||
func (a *Array) Value() Value {
|
func (a *Array) Value() Value {
|
||||||
|
if a.size == 0 {
|
||||||
|
delete(a.values, a.emptyValue.key)
|
||||||
|
}
|
||||||
|
|
||||||
// Query lists start a 1, so adjust the size first
|
// Query lists start a 1, so adjust the size first
|
||||||
a.size++
|
a.size++
|
||||||
prefix := a.prefix
|
prefix := a.prefix
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ import (
|
||||||
// the values must all be of the same type, and that map entries are ordered.
|
// the values must all be of the same type, and that map entries are ordered.
|
||||||
// A serialized map might look like the following:
|
// A serialized map might look like the following:
|
||||||
//
|
//
|
||||||
// MapName.entry.1.key=Foo
|
// MapName.entry.1.key=Foo
|
||||||
// &MapName.entry.1.value=spam
|
// &MapName.entry.1.value=spam
|
||||||
// &MapName.entry.2.key=Bar
|
// &MapName.entry.2.key=Bar
|
||||||
// &MapName.entry.2.value=eggs
|
// &MapName.entry.2.value=eggs
|
||||||
type Map struct {
|
type Map struct {
|
||||||
// The query values to add the map to.
|
// The query values to add the map to.
|
||||||
values url.Values
|
values url.Values
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ import (
|
||||||
// values where there is a fixed set of keys whose values each have their
|
// values where there is a fixed set of keys whose values each have their
|
||||||
// own known type. A serialized object might look like the following:
|
// own known type. A serialized object might look like the following:
|
||||||
//
|
//
|
||||||
// ObjectName.Foo=value
|
// ObjectName.Foo=value
|
||||||
// &ObjectName.Bar=5
|
// &ObjectName.Bar=5
|
||||||
type Object struct {
|
type Object struct {
|
||||||
// The query values to add the object to.
|
// The query values to add the object to.
|
||||||
values url.Values
|
values url.Values
|
||||||
|
|
|
||||||
|
|
@ -21,26 +21,18 @@ func GetErrorResponseComponents(r io.Reader, noErrorWrapping bool) (ErrorCompone
|
||||||
if err := xml.NewDecoder(r).Decode(&errResponse); err != nil && err != io.EOF {
|
if err := xml.NewDecoder(r).Decode(&errResponse); err != nil && err != io.EOF {
|
||||||
return ErrorComponents{}, fmt.Errorf("error while deserializing xml error response: %w", err)
|
return ErrorComponents{}, fmt.Errorf("error while deserializing xml error response: %w", err)
|
||||||
}
|
}
|
||||||
return ErrorComponents{
|
return ErrorComponents(errResponse), nil
|
||||||
Code: errResponse.Code,
|
|
||||||
Message: errResponse.Message,
|
|
||||||
RequestID: errResponse.RequestID,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var errResponse wrappedErrorResponse
|
var errResponse wrappedErrorResponse
|
||||||
if err := xml.NewDecoder(r).Decode(&errResponse); err != nil && err != io.EOF {
|
if err := xml.NewDecoder(r).Decode(&errResponse); err != nil && err != io.EOF {
|
||||||
return ErrorComponents{}, fmt.Errorf("error while deserializing xml error response: %w", err)
|
return ErrorComponents{}, fmt.Errorf("error while deserializing xml error response: %w", err)
|
||||||
}
|
}
|
||||||
return ErrorComponents{
|
return ErrorComponents(errResponse), nil
|
||||||
Code: errResponse.Code,
|
|
||||||
Message: errResponse.Message,
|
|
||||||
RequestID: errResponse.RequestID,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// noWrappedErrorResponse represents the error response body with
|
// noWrappedErrorResponse represents the error response body with
|
||||||
// no internal <Error></Error wrapping
|
// no internal Error wrapping
|
||||||
type noWrappedErrorResponse struct {
|
type noWrappedErrorResponse struct {
|
||||||
Code string `xml:"Code"`
|
Code string `xml:"Code"`
|
||||||
Message string `xml:"Message"`
|
Message string `xml:"Message"`
|
||||||
|
|
@ -48,7 +40,7 @@ type noWrappedErrorResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrappedErrorResponse represents the error response body
|
// wrappedErrorResponse represents the error response body
|
||||||
// wrapped within <Error>...</Error>
|
// wrapped within Error
|
||||||
type wrappedErrorResponse struct {
|
type wrappedErrorResponse struct {
|
||||||
Code string `xml:"Error>Code"`
|
Code string `xml:"Error>Code"`
|
||||||
Message string `xml:"Error>Message"`
|
Message string `xml:"Error>Message"`
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,6 @@ func NewTokenRateLimit(tokens uint) *TokenRateLimit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isTimeoutError(error) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type canceledError struct {
|
type canceledError struct {
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ func (a *AdaptiveMode) IsErrorRetryable(err error) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MaxAttempts returns the maximum number of attempts that can be made for
|
// MaxAttempts returns the maximum number of attempts that can be made for
|
||||||
// a attempt before failing. A value of 0 implies that the attempt should
|
// an attempt before failing. A value of 0 implies that the attempt should
|
||||||
// be retried until it succeeds if the errors are retryable.
|
// be retried until it succeeds if the errors are retryable.
|
||||||
func (a *AdaptiveMode) MaxAttempts() int {
|
func (a *AdaptiveMode) MaxAttempts() int {
|
||||||
return a.retryer.MaxAttempts()
|
return a.retryer.MaxAttempts()
|
||||||
|
|
@ -127,7 +127,7 @@ func (a *AdaptiveMode) GetInitialToken() (releaseToken func(error) error) {
|
||||||
|
|
||||||
// GetAttemptToken returns the attempt token that can be used to rate limit
|
// GetAttemptToken returns the attempt token that can be used to rate limit
|
||||||
// attempt calls. Will be used by the SDK's retry package's Attempt
|
// attempt calls. Will be used by the SDK's retry package's Attempt
|
||||||
// middleware to get a attempt token prior to calling the temp and releasing
|
// middleware to get an attempt token prior to calling the temp and releasing
|
||||||
// the attempt token after the attempt has been made.
|
// the attempt token after the attempt has been made.
|
||||||
func (a *AdaptiveMode) GetAttemptToken(ctx context.Context) (func(error) error, error) {
|
func (a *AdaptiveMode) GetAttemptToken(ctx context.Context) (func(error) error, error) {
|
||||||
for {
|
for {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
// Package retry provides interfaces and implementations for SDK request retry behavior.
|
// Package retry provides interfaces and implementations for SDK request retry behavior.
|
||||||
//
|
//
|
||||||
// Retryer Interface and Implementations
|
// # Retryer Interface and Implementations
|
||||||
//
|
//
|
||||||
// This packages defines Retryer interface that is used to either implement custom retry behavior
|
// This package defines Retryer interface that is used to either implement custom retry behavior
|
||||||
// or to extend the existing retry implementations provided by the SDK. This packages provides a single
|
// or to extend the existing retry implementations provided by the SDK. This package provides a single
|
||||||
// retry implementations: Standard.
|
// retry implementation: Standard.
|
||||||
//
|
//
|
||||||
// Standard
|
// # Standard
|
||||||
//
|
//
|
||||||
// Standard is the default retryer implementation used by service clients. The standard retryer is a rate limited
|
// Standard is the default retryer implementation used by service clients. The standard retryer is a rate limited
|
||||||
// retryer that has a configurable max attempts to limit the number of retry attempts when a retryable error occurs.
|
// retryer that has a configurable max attempts to limit the number of retry attempts when a retryable error occurs.
|
||||||
|
|
@ -15,66 +15,66 @@
|
||||||
//
|
//
|
||||||
// By default the standard retryer uses the DefaultRetryables slice of IsErrorRetryable types to determine whether
|
// By default the standard retryer uses the DefaultRetryables slice of IsErrorRetryable types to determine whether
|
||||||
// a given error is retryable. By default this list of retryables includes the following:
|
// a given error is retryable. By default this list of retryables includes the following:
|
||||||
// - Retrying errors that implement the RetryableError method, and return true.
|
// - Retrying errors that implement the RetryableError method, and return true.
|
||||||
// - Connection Errors
|
// - Connection Errors
|
||||||
// - Errors that implement a ConnectionError, Temporary, or Timeout method that return true.
|
// - Errors that implement a ConnectionError, Temporary, or Timeout method that return true.
|
||||||
// - Connection Reset Errors.
|
// - Connection Reset Errors.
|
||||||
// - net.OpErr types that are dialing errors or are temporary.
|
// - net.OpErr types that are dialing errors or are temporary.
|
||||||
// - HTTP Status Codes: 500, 502, 503, and 504.
|
// - HTTP Status Codes: 500, 502, 503, and 504.
|
||||||
// - API Error Codes
|
// - API Error Codes
|
||||||
// - RequestTimeout, RequestTimeoutException
|
// - RequestTimeout, RequestTimeoutException
|
||||||
// - Throttling, ThrottlingException, ThrottledException, RequestThrottledException, TooManyRequestsException,
|
// - Throttling, ThrottlingException, ThrottledException, RequestThrottledException, TooManyRequestsException,
|
||||||
// RequestThrottled, SlowDown, EC2ThrottledException
|
// RequestThrottled, SlowDown, EC2ThrottledException
|
||||||
// - ProvisionedThroughputExceededException, RequestLimitExceeded, BandwidthLimitExceeded, LimitExceededException
|
// - ProvisionedThroughputExceededException, RequestLimitExceeded, BandwidthLimitExceeded, LimitExceededException
|
||||||
// - TransactionInProgressException, PriorRequestNotComplete
|
// - TransactionInProgressException, PriorRequestNotComplete
|
||||||
//
|
//
|
||||||
// The standard retryer will not retry a request in the event if the context associated with the request
|
// The standard retryer will not retry a request in the event if the context associated with the request
|
||||||
// has been cancelled. Applications must handle this case explicitly if they wish to retry with a different context
|
// has been cancelled. Applications must handle this case explicitly if they wish to retry with a different context
|
||||||
// value.
|
// value.
|
||||||
//
|
//
|
||||||
// You can configure the standard retryer implementation to fit your applications by constructing a standard retryer
|
// You can configure the standard retryer implementation to fit your applications by constructing a standard retryer
|
||||||
// using the NewStandard function, and providing one more functional arguments that mutate the StandardOptions
|
// using the NewStandard function, and providing one more functional argument that mutate the StandardOptions
|
||||||
// structure. StandardOptions provides the ability to modify the token bucket rate limiter, retryable error conditions,
|
// structure. StandardOptions provides the ability to modify the token bucket rate limiter, retryable error conditions,
|
||||||
// and the retry delay policy.
|
// and the retry delay policy.
|
||||||
//
|
//
|
||||||
// For example to modify the default retry attempts for the standard retryer:
|
// For example to modify the default retry attempts for the standard retryer:
|
||||||
//
|
//
|
||||||
// // configure the custom retryer
|
// // configure the custom retryer
|
||||||
// customRetry := retry.NewStandard(func(o *retry.StandardOptions) {
|
// customRetry := retry.NewStandard(func(o *retry.StandardOptions) {
|
||||||
// o.MaxAttempts = 5
|
// o.MaxAttempts = 5
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// // create a service client with the retryer
|
// // create a service client with the retryer
|
||||||
// s3.NewFromConfig(cfg, func(o *s3.Options) {
|
// s3.NewFromConfig(cfg, func(o *s3.Options) {
|
||||||
// o.Retryer = customRetry
|
// o.Retryer = customRetry
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// Utilities
|
// # Utilities
|
||||||
//
|
//
|
||||||
// A number of package functions have been provided to easily wrap retryer implementations in an implementation agnostic
|
// A number of package functions have been provided to easily wrap retryer implementations in an implementation agnostic
|
||||||
// way. These are:
|
// way. These are:
|
||||||
//
|
//
|
||||||
// AddWithErrorCodes - Provides the ability to add additional API error codes that should be considered retryable
|
// AddWithErrorCodes - Provides the ability to add additional API error codes that should be considered retryable
|
||||||
// in addition to those considered retryable by the provided retryer.
|
// in addition to those considered retryable by the provided retryer.
|
||||||
//
|
//
|
||||||
// AddWithMaxAttempts - Provides the ability to set the max number of attempts for retrying a request by wrapping
|
// AddWithMaxAttempts - Provides the ability to set the max number of attempts for retrying a request by wrapping
|
||||||
// a retryer implementation.
|
// a retryer implementation.
|
||||||
//
|
//
|
||||||
// AddWithMaxBackoffDelay - Provides the ability to set the max back off delay that can occur before retrying a
|
// AddWithMaxBackoffDelay - Provides the ability to set the max back off delay that can occur before retrying a
|
||||||
// request by wrapping a retryer implementation.
|
// request by wrapping a retryer implementation.
|
||||||
//
|
//
|
||||||
// The following package functions have been provided to easily satisfy different retry interfaces to further customize
|
// The following package functions have been provided to easily satisfy different retry interfaces to further customize
|
||||||
// a given retryer's behavior:
|
// a given retryer's behavior:
|
||||||
//
|
//
|
||||||
// BackoffDelayerFunc - Can be used to wrap a function to satisfy the BackoffDelayer interface. For example,
|
// BackoffDelayerFunc - Can be used to wrap a function to satisfy the BackoffDelayer interface. For example,
|
||||||
// you can use this method to easily create custom back off policies to be used with the
|
// you can use this method to easily create custom back off policies to be used with the
|
||||||
// standard retryer.
|
// standard retryer.
|
||||||
//
|
//
|
||||||
// IsErrorRetryableFunc - Can be used to wrap a function to satisfy the IsErrorRetryable interface. For example,
|
// IsErrorRetryableFunc - Can be used to wrap a function to satisfy the IsErrorRetryable interface. For example,
|
||||||
// this can be used to extend the standard retryer to add additional logic ot determine if a
|
// this can be used to extend the standard retryer to add additional logic to determine if an
|
||||||
// error should be retried.
|
// error should be retried.
|
||||||
//
|
//
|
||||||
// IsErrorTimeoutFunc - Can be used to wrap a function to satisfy IsErrorTimeout interface. For example,
|
// IsErrorTimeoutFunc - Can be used to wrap a function to satisfy IsErrorTimeout interface. For example,
|
||||||
// this can be used to extend the standard retryer to add additional logic to determine if an
|
// this can be used to extend the standard retryer to add additional logic to determine if an
|
||||||
// error should be considered a timeout.
|
// error should be considered a timeout.
|
||||||
package retry
|
package retry
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import (
|
||||||
awsmiddle "github.com/aws/aws-sdk-go-v2/aws/middleware"
|
awsmiddle "github.com/aws/aws-sdk-go-v2/aws/middleware"
|
||||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||||
"github.com/aws/smithy-go/logging"
|
"github.com/aws/smithy-go/logging"
|
||||||
"github.com/aws/smithy-go/middleware"
|
|
||||||
smithymiddle "github.com/aws/smithy-go/middleware"
|
smithymiddle "github.com/aws/smithy-go/middleware"
|
||||||
"github.com/aws/smithy-go/transport/http"
|
"github.com/aws/smithy-go/transport/http"
|
||||||
)
|
)
|
||||||
|
|
@ -90,7 +89,7 @@ func (r *Attempt) HandleFinalize(ctx context.Context, in smithymiddle.FinalizeIn
|
||||||
out, attemptResult, releaseRetryToken, err = r.handleAttempt(attemptCtx, attemptInput, releaseRetryToken, next)
|
out, attemptResult, releaseRetryToken, err = r.handleAttempt(attemptCtx, attemptInput, releaseRetryToken, next)
|
||||||
attemptClockSkew, _ = awsmiddle.GetAttemptSkew(attemptResult.ResponseMetadata)
|
attemptClockSkew, _ = awsmiddle.GetAttemptSkew(attemptResult.ResponseMetadata)
|
||||||
|
|
||||||
// AttempResult Retried states that the attempt was not successful, and
|
// AttemptResult Retried states that the attempt was not successful, and
|
||||||
// should be retried.
|
// should be retried.
|
||||||
shouldRetry := attemptResult.Retried
|
shouldRetry := attemptResult.Retried
|
||||||
|
|
||||||
|
|
@ -292,7 +291,7 @@ type retryMetadataKey struct{}
|
||||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||||
// to clear all stack values.
|
// to clear all stack values.
|
||||||
func getRetryMetadata(ctx context.Context) (metadata retryMetadata, ok bool) {
|
func getRetryMetadata(ctx context.Context) (metadata retryMetadata, ok bool) {
|
||||||
metadata, ok = middleware.GetStackValue(ctx, retryMetadataKey{}).(retryMetadata)
|
metadata, ok = smithymiddle.GetStackValue(ctx, retryMetadataKey{}).(retryMetadata)
|
||||||
return metadata, ok
|
return metadata, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,7 +300,7 @@ func getRetryMetadata(ctx context.Context) (metadata retryMetadata, ok bool) {
|
||||||
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
|
||||||
// to clear all stack values.
|
// to clear all stack values.
|
||||||
func setRetryMetadata(ctx context.Context, metadata retryMetadata) context.Context {
|
func setRetryMetadata(ctx context.Context, metadata retryMetadata) context.Context {
|
||||||
return middleware.WithStackValue(ctx, retryMetadataKey{}, metadata)
|
return smithymiddle.WithStackValue(ctx, retryMetadataKey{}, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRetryMiddlewaresOptions is the set of options that can be passed to
|
// AddRetryMiddlewaresOptions is the set of options that can be passed to
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,13 @@ func (r RetryableConnectionError) IsErrorRetryable(err error) aws.Ternary {
|
||||||
var timeoutErr interface{ Timeout() bool }
|
var timeoutErr interface{ Timeout() bool }
|
||||||
var urlErr *url.Error
|
var urlErr *url.Error
|
||||||
var netOpErr *net.OpError
|
var netOpErr *net.OpError
|
||||||
|
var dnsError *net.DNSError
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
case errors.As(err, &dnsError):
|
||||||
|
// NXDOMAIN errors should not be retried
|
||||||
|
retryable = !dnsError.IsNotFound && dnsError.IsTemporary
|
||||||
|
|
||||||
case errors.As(err, &conErr) && conErr.ConnectionError():
|
case errors.As(err, &conErr) && conErr.ConnectionError():
|
||||||
retryable = true
|
retryable = true
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ type Retryer interface {
|
||||||
IsErrorRetryable(error) bool
|
IsErrorRetryable(error) bool
|
||||||
|
|
||||||
// MaxAttempts returns the maximum number of attempts that can be made for
|
// MaxAttempts returns the maximum number of attempts that can be made for
|
||||||
// a attempt before failing. A value of 0 implies that the attempt should
|
// an attempt before failing. A value of 0 implies that the attempt should
|
||||||
// be retried until it succeeds if the errors are retryable.
|
// be retried until it succeeds if the errors are retryable.
|
||||||
MaxAttempts() int
|
MaxAttempts() int
|
||||||
|
|
||||||
|
|
@ -66,7 +66,7 @@ type Retryer interface {
|
||||||
GetInitialToken() (releaseToken func(error) error)
|
GetInitialToken() (releaseToken func(error) error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetryerV2 is an interface to determine if a given error from a attempt
|
// RetryerV2 is an interface to determine if a given error from an attempt
|
||||||
// should be retried, and if so what backoff delay to apply. The default
|
// should be retried, and if so what backoff delay to apply. The default
|
||||||
// implementation used by most services is the retry package's Standard type.
|
// implementation used by most services is the retry package's Standard type.
|
||||||
// Which contains basic retry logic using exponential backoff.
|
// Which contains basic retry logic using exponential backoff.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ var IgnoredHeaders = Rules{
|
||||||
"Authorization": struct{}{},
|
"Authorization": struct{}{},
|
||||||
"User-Agent": struct{}{},
|
"User-Agent": struct{}{},
|
||||||
"X-Amzn-Trace-Id": struct{}{},
|
"X-Amzn-Trace-Id": struct{}{},
|
||||||
|
"Expect": struct{}{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,19 +46,35 @@ func StripExcessSpaces(str string) string {
|
||||||
return string(buf[:m])
|
return string(buf[:m])
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetURIPath returns the escaped URI component from the provided URL
|
// GetURIPath returns the escaped URI component from the provided URL.
|
||||||
func GetURIPath(u *url.URL) string {
|
func GetURIPath(u *url.URL) string {
|
||||||
var uri string
|
var uriPath string
|
||||||
|
|
||||||
if len(u.Opaque) > 0 {
|
if len(u.Opaque) > 0 {
|
||||||
uri = "/" + strings.Join(strings.Split(u.Opaque, "/")[3:], "/")
|
const schemeSep, pathSep, queryStart = "//", "/", "?"
|
||||||
|
|
||||||
|
opaque := u.Opaque
|
||||||
|
// Cut off the query string if present.
|
||||||
|
if idx := strings.Index(opaque, queryStart); idx >= 0 {
|
||||||
|
opaque = opaque[:idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cutout the scheme separator if present.
|
||||||
|
if strings.Index(opaque, schemeSep) == 0 {
|
||||||
|
opaque = opaque[len(schemeSep):]
|
||||||
|
}
|
||||||
|
|
||||||
|
// capture URI path starting with first path separator.
|
||||||
|
if idx := strings.Index(opaque, pathSep); idx >= 0 {
|
||||||
|
uriPath = opaque[idx:]
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uri = u.EscapedPath()
|
uriPath = u.EscapedPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(uri) == 0 {
|
if len(uriPath) == 0 {
|
||||||
uri = "/"
|
uriPath = "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
return uri
|
return uriPath
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ func (m *dynamicPayloadSigningMiddleware) HandleBuild(
|
||||||
}
|
}
|
||||||
|
|
||||||
// if TLS is enabled, use unsigned payload when supported
|
// if TLS is enabled, use unsigned payload when supported
|
||||||
if strings.EqualFold(req.URL.Scheme, "https") {
|
if req.IsHTTPS() {
|
||||||
return (&unsignedPayload{}).HandleBuild(ctx, in, next)
|
return (&unsignedPayload{}).HandleBuild(ctx, in, next)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -371,13 +371,8 @@ func haveCredentialProvider(p aws.CredentialsProvider) bool {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
switch p.(type) {
|
|
||||||
case aws.AnonymousCredentials,
|
|
||||||
*aws.AnonymousCredentials:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return !aws.IsCredentialsProvider(p, (*aws.AnonymousCredentials)(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
type payloadHashKey struct{}
|
type payloadHashKey struct{}
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,22 @@
|
||||||
// Provides request signing for request that need to be signed with
|
// Provides request signing for request that need to be signed with
|
||||||
// AWS V4 Signatures.
|
// AWS V4 Signatures.
|
||||||
//
|
//
|
||||||
// Standalone Signer
|
// # Standalone Signer
|
||||||
//
|
//
|
||||||
// Generally using the signer outside of the SDK should not require any additional
|
// Generally using the signer outside of the SDK should not require any additional
|
||||||
// The signer does this by taking advantage of the URL.EscapedPath method. If your request URI requires
|
//
|
||||||
|
// The signer does this by taking advantage of the URL.EscapedPath method. If your request URI requires
|
||||||
|
//
|
||||||
// additional escaping you many need to use the URL.Opaque to define what the raw URI should be sent
|
// additional escaping you many need to use the URL.Opaque to define what the raw URI should be sent
|
||||||
// to the service as.
|
// to the service as.
|
||||||
//
|
//
|
||||||
// The signer will first check the URL.Opaque field, and use its value if set.
|
// The signer will first check the URL.Opaque field, and use its value if set.
|
||||||
// The signer does require the URL.Opaque field to be set in the form of:
|
// The signer does require the URL.Opaque field to be set in the form of:
|
||||||
//
|
//
|
||||||
// "//<hostname>/<path>"
|
// "//<hostname>/<path>"
|
||||||
//
|
//
|
||||||
// // e.g.
|
// // e.g.
|
||||||
// "//example.com/some/path"
|
// "//example.com/some/path"
|
||||||
//
|
//
|
||||||
// The leading "//" and hostname are required or the URL.Opaque escaping will
|
// The leading "//" and hostname are required or the URL.Opaque escaping will
|
||||||
// not work correctly.
|
// not work correctly.
|
||||||
|
|
@ -252,7 +254,7 @@ func buildAuthorizationHeader(credentialStr, signedHeadersStr, signingSignature
|
||||||
// request has no payload you should use the hex encoded SHA-256 of an empty
|
// request has no payload you should use the hex encoded SHA-256 of an empty
|
||||||
// string as the payloadHash value.
|
// string as the payloadHash value.
|
||||||
//
|
//
|
||||||
// "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
// "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||||
//
|
//
|
||||||
// Some services such as Amazon S3 accept alternative values for the payload
|
// Some services such as Amazon S3 accept alternative values for the payload
|
||||||
// hash, such as "UNSIGNED-PAYLOAD" for requests where the body will not be
|
// hash, such as "UNSIGNED-PAYLOAD" for requests where the body will not be
|
||||||
|
|
@ -311,7 +313,7 @@ func (s Signer) SignHTTP(ctx context.Context, credentials aws.Credentials, r *ht
|
||||||
// request has no payload you should use the hex encoded SHA-256 of an empty
|
// request has no payload you should use the hex encoded SHA-256 of an empty
|
||||||
// string as the payloadHash value.
|
// string as the payloadHash value.
|
||||||
//
|
//
|
||||||
// "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
// "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||||
//
|
//
|
||||||
// Some services such as Amazon S3 accept alternative values for the payload
|
// Some services such as Amazon S3 accept alternative values for the payload
|
||||||
// hash, such as "UNSIGNED-PAYLOAD" for requests where the body will not be
|
// hash, such as "UNSIGNED-PAYLOAD" for requests where the body will not be
|
||||||
|
|
@ -331,10 +333,10 @@ func (s Signer) SignHTTP(ctx context.Context, credentials aws.Credentials, r *ht
|
||||||
// parameter is not used by all AWS services, and is most notable used by
|
// parameter is not used by all AWS services, and is most notable used by
|
||||||
// Amazon S3 APIs.
|
// Amazon S3 APIs.
|
||||||
//
|
//
|
||||||
// expires := 20 * time.Minute
|
// expires := 20 * time.Minute
|
||||||
// query := req.URL.Query()
|
// query := req.URL.Query()
|
||||||
// query.Set("X-Amz-Expires", strconv.FormatInt(int64(expires/time.Second), 10)
|
// query.Set("X-Amz-Expires", strconv.FormatInt(int64(expires/time.Second), 10)
|
||||||
// req.URL.RawQuery = query.Encode()
|
// req.URL.RawQuery = query.Encode()
|
||||||
//
|
//
|
||||||
// This method does not modify the provided request.
|
// This method does not modify the provided request.
|
||||||
func (s *Signer) PresignHTTP(
|
func (s *Signer) PresignHTTP(
|
||||||
|
|
@ -407,8 +409,8 @@ func (s *httpSigner) buildCanonicalHeaders(host string, rule v4Internal.Rule, he
|
||||||
headers = append(headers, hostHeader)
|
headers = append(headers, hostHeader)
|
||||||
signed[hostHeader] = append(signed[hostHeader], host)
|
signed[hostHeader] = append(signed[hostHeader], host)
|
||||||
|
|
||||||
|
const contentLengthHeader = "content-length"
|
||||||
if length > 0 {
|
if length > 0 {
|
||||||
const contentLengthHeader = "content-length"
|
|
||||||
headers = append(headers, contentLengthHeader)
|
headers = append(headers, contentLengthHeader)
|
||||||
signed[contentLengthHeader] = append(signed[contentLengthHeader], strconv.FormatInt(length, 10))
|
signed[contentLengthHeader] = append(signed[contentLengthHeader], strconv.FormatInt(length, 10))
|
||||||
}
|
}
|
||||||
|
|
@ -417,6 +419,10 @@ func (s *httpSigner) buildCanonicalHeaders(host string, rule v4Internal.Rule, he
|
||||||
if !rule.IsValid(k) {
|
if !rule.IsValid(k) {
|
||||||
continue // ignored header
|
continue // ignored header
|
||||||
}
|
}
|
||||||
|
if strings.EqualFold(k, contentLengthHeader) {
|
||||||
|
// prevent signing already handled content-length header.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
lowerCaseKey := strings.ToLower(k)
|
lowerCaseKey := strings.ToLower(k)
|
||||||
if _, ok := signed[lowerCaseKey]; ok {
|
if _, ok := signed[lowerCaseKey]; ok {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,214 @@
|
||||||
|
# v1.18.25 (2023-05-09)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.24 (2023-05-08)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.23 (2023-05-04)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.22 (2023-04-24)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.21 (2023-04-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.20 (2023-04-07)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.19 (2023-03-21)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.18 (2023-03-16)
|
||||||
|
|
||||||
|
* **Bug Fix**: Allow RoleARN to be set as functional option on STS WebIdentityRoleOptions. Fixes aws/aws-sdk-go-v2#2015.
|
||||||
|
|
||||||
|
# v1.18.17 (2023-03-14)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.16 (2023-03-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.15 (2023-02-22)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.14 (2023-02-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.13 (2023-02-15)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.12 (2023-02-03)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.11 (2023-02-01)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.10 (2023-01-25)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.9 (2023-01-23)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.8 (2023-01-05)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.7 (2022-12-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.6 (2022-12-19)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.5 (2022-12-15)
|
||||||
|
|
||||||
|
* **Bug Fix**: Unify logic between shared config and in finding home directory
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.4 (2022-12-02)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.3 (2022-11-22)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.2 (2022-11-17)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.1 (2022-11-16)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.18.0 (2022-11-11)
|
||||||
|
|
||||||
|
* **Announcement**: When using the SSOTokenProvider, a previous implementation incorrectly compensated for invalid SSOTokenProvider configurations in the shared profile. This has been fixed via PR #1903 and tracked in issue #1846
|
||||||
|
* **Feature**: Adds token refresh support (via SSOTokenProvider) when using the SSOCredentialProvider
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.11 (2022-11-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.10 (2022-10-24)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.9 (2022-10-21)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.8 (2022-09-30)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.7 (2022-09-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.6 (2022-09-14)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.5 (2022-09-02)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.4 (2022-08-31)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.3 (2022-08-30)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.2 (2022-08-29)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.1 (2022-08-15)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.17.0 (2022-08-14)
|
||||||
|
|
||||||
|
* **Feature**: Add alternative mechanism for determning the users `$HOME` or `%USERPROFILE%` location when the environment variables are not present.
|
||||||
|
|
||||||
|
# v1.16.1 (2022-08-11)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.16.0 (2022-08-10)
|
||||||
|
|
||||||
|
* **Feature**: Adds support for the following settings in the `~/.aws/credentials` file: `sso_account_id`, `sso_region`, `sso_role_name`, `sso_start_url`, and `ca_bundle`.
|
||||||
|
|
||||||
|
# v1.15.17 (2022-08-09)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.16 (2022-08-08)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.15 (2022-08-01)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.14 (2022-07-11)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.13 (2022-07-05)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.12 (2022-06-29)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.11 (2022-06-16)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.10 (2022-06-07)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.9 (2022-05-26)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.8 (2022-05-25)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.7 (2022-05-17)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.15.6 (2022-05-16)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
# v1.15.5 (2022-05-09)
|
# v1.15.5 (2022-05-09)
|
||||||
|
|
||||||
* **Bug Fix**: Fixes a bug in LoadDefaultConfig to correctly assign ConfigSources so all config resolvers have access to the config sources. This fixes the feature/ec2/imds client not having configuration applied via config.LoadOptions such as EC2IMDSClientEnableState. PR [#1682](https://github.com/aws/aws-sdk-go-v2/pull/1682)
|
* **Bug Fix**: Fixes a bug in LoadDefaultConfig to correctly assign ConfigSources so all config resolvers have access to the config sources. This fixes the feature/ec2/imds client not having configuration applied via config.LoadOptions such as EC2IMDSClientEnableState. PR [#1682](https://github.com/aws/aws-sdk-go-v2/pull/1682)
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,10 @@ var defaultAWSConfigResolvers = []awsConfigResolver{
|
||||||
// implementations depend on or can be configured with earlier resolved
|
// implementations depend on or can be configured with earlier resolved
|
||||||
// configuration options.
|
// configuration options.
|
||||||
resolveCredentials,
|
resolveCredentials,
|
||||||
|
|
||||||
|
// Sets the resolved bearer authentication token API clients will use for
|
||||||
|
// httpBearerAuth authentication scheme.
|
||||||
|
resolveBearerAuthToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Config represents a generic configuration value or set of values. This type
|
// A Config represents a generic configuration value or set of values. This type
|
||||||
|
|
@ -162,13 +166,12 @@ func (cs configs) ResolveConfig(f func(configs []interface{}) error) error {
|
||||||
// The custom configurations must satisfy the respective providers for their data
|
// The custom configurations must satisfy the respective providers for their data
|
||||||
// or the custom data will be ignored by the resolvers and config loaders.
|
// or the custom data will be ignored by the resolvers and config loaders.
|
||||||
//
|
//
|
||||||
// cfg, err := config.LoadDefaultConfig( context.TODO(),
|
// cfg, err := config.LoadDefaultConfig( context.TODO(),
|
||||||
// WithSharedConfigProfile("test-profile"),
|
// WithSharedConfigProfile("test-profile"),
|
||||||
// )
|
// )
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// panic(fmt.Sprintf("failed loading config, %v", err))
|
// panic(fmt.Sprintf("failed loading config, %v", err))
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
//
|
//
|
||||||
// The default configuration sources are:
|
// The default configuration sources are:
|
||||||
// * Environment Variables
|
// * Environment Variables
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,6 @@
|
||||||
// take precedence over the default environment and shared config sources used by the SDK. If one or more Config sources
|
// take precedence over the default environment and shared config sources used by the SDK. If one or more Config sources
|
||||||
// implement the same provider interface, priority will be handled by the order in which the sources were passed in.
|
// implement the same provider interface, priority will be handled by the order in which the sources were passed in.
|
||||||
//
|
//
|
||||||
// A number of helpers (prefixed by ``With``) are provided in this package that implement their respective provider
|
// A number of helpers (prefixed by “With“) are provided in this package that implement their respective provider
|
||||||
// interface. These helpers should be used for overriding configuration programmatically at runtime.
|
// interface. These helpers should be used for overriding configuration programmatically at runtime.
|
||||||
package config
|
package config
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,4 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
// goModuleVersion is the tagged release for this module
|
// goModuleVersion is the tagged release for this module
|
||||||
const goModuleVersion = "1.15.5"
|
const goModuleVersion = "1.18.25"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go-v2/credentials/ssocreds"
|
"github.com/aws/aws-sdk-go-v2/credentials/ssocreds"
|
||||||
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
|
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
|
||||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||||
|
smithybearer "github.com/aws/smithy-go/auth/bearer"
|
||||||
"github.com/aws/smithy-go/logging"
|
"github.com/aws/smithy-go/logging"
|
||||||
"github.com/aws/smithy-go/middleware"
|
"github.com/aws/smithy-go/middleware"
|
||||||
)
|
)
|
||||||
|
|
@ -28,6 +29,9 @@ type LoadOptions struct {
|
||||||
// Credentials object to use when signing requests.
|
// Credentials object to use when signing requests.
|
||||||
Credentials aws.CredentialsProvider
|
Credentials aws.CredentialsProvider
|
||||||
|
|
||||||
|
// Token provider for authentication operations with bearer authentication.
|
||||||
|
BearerAuthTokenProvider smithybearer.TokenProvider
|
||||||
|
|
||||||
// HTTPClient the SDK's API clients will use to invoke HTTP requests.
|
// HTTPClient the SDK's API clients will use to invoke HTTP requests.
|
||||||
HTTPClient HTTPClient
|
HTTPClient HTTPClient
|
||||||
|
|
||||||
|
|
@ -128,6 +132,14 @@ type LoadOptions struct {
|
||||||
// aws.CredentialsCacheOptions
|
// aws.CredentialsCacheOptions
|
||||||
CredentialsCacheOptions func(*aws.CredentialsCacheOptions)
|
CredentialsCacheOptions func(*aws.CredentialsCacheOptions)
|
||||||
|
|
||||||
|
// BearerAuthTokenCacheOptions is a function for setting the smithy-go
|
||||||
|
// auth/bearer#TokenCacheOptions
|
||||||
|
BearerAuthTokenCacheOptions func(*smithybearer.TokenCacheOptions)
|
||||||
|
|
||||||
|
// SSOTokenProviderOptions is a function for setting the
|
||||||
|
// credentials/ssocreds.SSOTokenProviderOptions
|
||||||
|
SSOTokenProviderOptions func(*ssocreds.SSOTokenProviderOptions)
|
||||||
|
|
||||||
// ProcessCredentialOptions is a function for setting
|
// ProcessCredentialOptions is a function for setting
|
||||||
// the processcreds.Options
|
// the processcreds.Options
|
||||||
ProcessCredentialOptions func(*processcreds.Options)
|
ProcessCredentialOptions func(*processcreds.Options)
|
||||||
|
|
@ -451,6 +463,73 @@ func WithCredentialsCacheOptions(v func(*aws.CredentialsCacheOptions)) LoadOptio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getBearerAuthTokenProvider returns the credentials value
|
||||||
|
func (o LoadOptions) getBearerAuthTokenProvider(ctx context.Context) (smithybearer.TokenProvider, bool, error) {
|
||||||
|
if o.BearerAuthTokenProvider == nil {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.BearerAuthTokenProvider, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBearerAuthTokenProvider is a helper function to construct functional options
|
||||||
|
// that sets Credential provider value on config's LoadOptions. If credentials
|
||||||
|
// provider is set to nil, the credentials provider value will be ignored.
|
||||||
|
// If multiple WithBearerAuthTokenProvider calls are made, the last call overrides
|
||||||
|
// the previous call values.
|
||||||
|
func WithBearerAuthTokenProvider(v smithybearer.TokenProvider) LoadOptionsFunc {
|
||||||
|
return func(o *LoadOptions) error {
|
||||||
|
o.BearerAuthTokenProvider = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getBearerAuthTokenCacheOptionsProvider returns the wrapped function to set smithybearer.TokenCacheOptions
|
||||||
|
func (o LoadOptions) getBearerAuthTokenCacheOptions(ctx context.Context) (func(*smithybearer.TokenCacheOptions), bool, error) {
|
||||||
|
if o.BearerAuthTokenCacheOptions == nil {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.BearerAuthTokenCacheOptions, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBearerAuthTokenCacheOptions is a helper function to construct functional options
|
||||||
|
// that sets a function to modify the TokenCacheOptions the smithy-go
|
||||||
|
// auth/bearer#TokenCache will be configured with, if the TokenCache is used by
|
||||||
|
// the configuration loader.
|
||||||
|
//
|
||||||
|
// If multiple WithBearerAuthTokenCacheOptions calls are made, the last call overrides
|
||||||
|
// the previous call values.
|
||||||
|
func WithBearerAuthTokenCacheOptions(v func(*smithybearer.TokenCacheOptions)) LoadOptionsFunc {
|
||||||
|
return func(o *LoadOptions) error {
|
||||||
|
o.BearerAuthTokenCacheOptions = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSSOTokenProviderOptionsProvider returns the wrapped function to set smithybearer.TokenCacheOptions
|
||||||
|
func (o LoadOptions) getSSOTokenProviderOptions(ctx context.Context) (func(*ssocreds.SSOTokenProviderOptions), bool, error) {
|
||||||
|
if o.SSOTokenProviderOptions == nil {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.SSOTokenProviderOptions, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSSOTokenProviderOptions is a helper function to construct functional
|
||||||
|
// options that sets a function to modify the SSOtokenProviderOptions the SDK's
|
||||||
|
// credentials/ssocreds#SSOProvider will be configured with, if the
|
||||||
|
// SSOTokenProvider is used by the configuration loader.
|
||||||
|
//
|
||||||
|
// If multiple WithSSOTokenProviderOptions calls are made, the last call overrides
|
||||||
|
// the previous call values.
|
||||||
|
func WithSSOTokenProviderOptions(v func(*ssocreds.SSOTokenProviderOptions)) LoadOptionsFunc {
|
||||||
|
return func(o *LoadOptions) error {
|
||||||
|
o.SSOTokenProviderOptions = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// getProcessCredentialOptions returns the wrapped function to set processcreds.Options
|
// getProcessCredentialOptions returns the wrapped function to set processcreds.Options
|
||||||
func (o LoadOptions) getProcessCredentialOptions(ctx context.Context) (func(*processcreds.Options), bool, error) {
|
func (o LoadOptions) getProcessCredentialOptions(ctx context.Context) (func(*processcreds.Options), bool, error) {
|
||||||
if o.ProcessCredentialOptions == nil {
|
if o.ProcessCredentialOptions == nil {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go-v2/credentials/ssocreds"
|
"github.com/aws/aws-sdk-go-v2/credentials/ssocreds"
|
||||||
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
|
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
|
||||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||||
|
smithybearer "github.com/aws/smithy-go/auth/bearer"
|
||||||
"github.com/aws/smithy-go/logging"
|
"github.com/aws/smithy-go/logging"
|
||||||
"github.com/aws/smithy-go/middleware"
|
"github.com/aws/smithy-go/middleware"
|
||||||
)
|
)
|
||||||
|
|
@ -185,6 +186,73 @@ func getCredentialsCacheOptionsProvider(ctx context.Context, configs configs) (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bearerAuthTokenProviderProvider provides access to the bearer authentication
|
||||||
|
// token external configuration value.
|
||||||
|
type bearerAuthTokenProviderProvider interface {
|
||||||
|
getBearerAuthTokenProvider(context.Context) (smithybearer.TokenProvider, bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getBearerAuthTokenProvider searches the config sources for a
|
||||||
|
// bearerAuthTokenProviderProvider and returns the value if found. Returns an
|
||||||
|
// error if a provider fails before a value is found.
|
||||||
|
func getBearerAuthTokenProvider(ctx context.Context, configs configs) (p smithybearer.TokenProvider, found bool, err error) {
|
||||||
|
for _, cfg := range configs {
|
||||||
|
if provider, ok := cfg.(bearerAuthTokenProviderProvider); ok {
|
||||||
|
p, found, err = provider.getBearerAuthTokenProvider(ctx)
|
||||||
|
if err != nil || found {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// bearerAuthTokenCacheOptionsProvider is an interface for retrieving a function for
|
||||||
|
// setting the smithy-go auth/bearer#TokenCacheOptions.
|
||||||
|
type bearerAuthTokenCacheOptionsProvider interface {
|
||||||
|
getBearerAuthTokenCacheOptions(context.Context) (func(*smithybearer.TokenCacheOptions), bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getBearerAuthTokenCacheOptionsProvider is an interface for retrieving a function for
|
||||||
|
// setting the smithy-go auth/bearer#TokenCacheOptions.
|
||||||
|
func getBearerAuthTokenCacheOptions(ctx context.Context, configs configs) (
|
||||||
|
f func(*smithybearer.TokenCacheOptions), found bool, err error,
|
||||||
|
) {
|
||||||
|
for _, config := range configs {
|
||||||
|
if p, ok := config.(bearerAuthTokenCacheOptionsProvider); ok {
|
||||||
|
f, found, err = p.getBearerAuthTokenCacheOptions(ctx)
|
||||||
|
if err != nil || found {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ssoTokenProviderOptionsProvider is an interface for retrieving a function for
|
||||||
|
// setting the SDK's credentials/ssocreds#SSOTokenProviderOptions.
|
||||||
|
type ssoTokenProviderOptionsProvider interface {
|
||||||
|
getSSOTokenProviderOptions(context.Context) (func(*ssocreds.SSOTokenProviderOptions), bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSSOTokenProviderOptions is an interface for retrieving a function for
|
||||||
|
// setting the SDK's credentials/ssocreds#SSOTokenProviderOptions.
|
||||||
|
func getSSOTokenProviderOptions(ctx context.Context, configs configs) (
|
||||||
|
f func(*ssocreds.SSOTokenProviderOptions), found bool, err error,
|
||||||
|
) {
|
||||||
|
for _, config := range configs {
|
||||||
|
if p, ok := config.(ssoTokenProviderOptionsProvider); ok {
|
||||||
|
f, found, err = p.getSSOTokenProviderOptions(ctx)
|
||||||
|
if err != nil || found {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ssoTokenProviderOptionsProvider
|
||||||
|
|
||||||
// processCredentialOptions is an interface for retrieving a function for setting
|
// processCredentialOptions is an interface for retrieving a function for setting
|
||||||
// the processcreds.Options.
|
// the processcreds.Options.
|
||||||
type processCredentialOptions interface {
|
type processCredentialOptions interface {
|
||||||
|
|
|
||||||
122
vendor/github.com/aws/aws-sdk-go-v2/config/resolve_bearer_token.go
generated
vendored
Normal file
122
vendor/github.com/aws/aws-sdk-go-v2/config/resolve_bearer_token.go
generated
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/credentials/ssocreds"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/ssooidc"
|
||||||
|
smithybearer "github.com/aws/smithy-go/auth/bearer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// resolveBearerAuthToken extracts a token provider from the config sources.
|
||||||
|
//
|
||||||
|
// If an explicit bearer authentication token provider is not found the
|
||||||
|
// resolver will fallback to resolving token provider via other config sources
|
||||||
|
// such as SharedConfig.
|
||||||
|
func resolveBearerAuthToken(ctx context.Context, cfg *aws.Config, configs configs) error {
|
||||||
|
found, err := resolveBearerAuthTokenProvider(ctx, cfg, configs)
|
||||||
|
if found || err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolveBearerAuthTokenProviderChain(ctx, cfg, configs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveBearerAuthTokenProvider extracts the first instance of
|
||||||
|
// BearerAuthTokenProvider from the config sources.
|
||||||
|
//
|
||||||
|
// The resolved BearerAuthTokenProvider will be wrapped in a cache to ensure
|
||||||
|
// the Token is only refreshed when needed. This also protects the
|
||||||
|
// TokenProvider so it can be used concurrently.
|
||||||
|
//
|
||||||
|
// Config providers used:
|
||||||
|
// * bearerAuthTokenProviderProvider
|
||||||
|
func resolveBearerAuthTokenProvider(ctx context.Context, cfg *aws.Config, configs configs) (bool, error) {
|
||||||
|
tokenProvider, found, err := getBearerAuthTokenProvider(ctx, configs)
|
||||||
|
if !found || err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.BearerAuthTokenProvider, err = wrapWithBearerAuthTokenCache(
|
||||||
|
ctx, configs, tokenProvider)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveBearerAuthTokenProviderChain(ctx context.Context, cfg *aws.Config, configs configs) (err error) {
|
||||||
|
_, sharedConfig, _ := getAWSConfigSources(configs)
|
||||||
|
|
||||||
|
var provider smithybearer.TokenProvider
|
||||||
|
|
||||||
|
if sharedConfig.SSOSession != nil {
|
||||||
|
provider, err = resolveBearerAuthSSOTokenProvider(
|
||||||
|
ctx, cfg, sharedConfig.SSOSession, configs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil && provider != nil {
|
||||||
|
cfg.BearerAuthTokenProvider, err = wrapWithBearerAuthTokenCache(
|
||||||
|
ctx, configs, provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveBearerAuthSSOTokenProvider(ctx context.Context, cfg *aws.Config, session *SSOSession, configs configs) (*ssocreds.SSOTokenProvider, error) {
|
||||||
|
ssoTokenProviderOptionsFn, found, err := getSSOTokenProviderOptions(ctx, configs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get SSOTokenProviderOptions from config sources, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var optFns []func(*ssocreds.SSOTokenProviderOptions)
|
||||||
|
if found {
|
||||||
|
optFns = append(optFns, ssoTokenProviderOptionsFn)
|
||||||
|
}
|
||||||
|
|
||||||
|
cachePath, err := ssocreds.StandardCachedTokenFilepath(session.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get SSOTokenProvider's cache path, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := ssooidc.NewFromConfig(*cfg)
|
||||||
|
provider := ssocreds.NewSSOTokenProvider(client, cachePath, optFns...)
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrapWithBearerAuthTokenCache will wrap provider with an smithy-go
|
||||||
|
// bearer/auth#TokenCache with the provided options if the provider is not
|
||||||
|
// already a TokenCache.
|
||||||
|
func wrapWithBearerAuthTokenCache(
|
||||||
|
ctx context.Context,
|
||||||
|
cfgs configs,
|
||||||
|
provider smithybearer.TokenProvider,
|
||||||
|
optFns ...func(*smithybearer.TokenCacheOptions),
|
||||||
|
) (smithybearer.TokenProvider, error) {
|
||||||
|
_, ok := provider.(*smithybearer.TokenCache)
|
||||||
|
if ok {
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenCacheConfigOptions, optionsFound, err := getBearerAuthTokenCacheOptions(ctx, cfgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := make([]func(*smithybearer.TokenCacheOptions), 0, 2+len(optFns))
|
||||||
|
opts = append(opts, func(o *smithybearer.TokenCacheOptions) {
|
||||||
|
o.RefreshBeforeExpires = 5 * time.Minute
|
||||||
|
o.RetrieveBearerTokenTimeout = 30 * time.Second
|
||||||
|
})
|
||||||
|
opts = append(opts, optFns...)
|
||||||
|
if optionsFound {
|
||||||
|
opts = append(opts, tokenCacheConfigOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
return smithybearer.NewTokenCache(provider, opts...), nil
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
|
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
|
||||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/sso"
|
"github.com/aws/aws-sdk-go-v2/service/sso"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/ssooidc"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -29,25 +30,19 @@ var (
|
||||||
ecsContainerEndpoint = "http://169.254.170.2" // not constant to allow for swapping during unit-testing
|
ecsContainerEndpoint = "http://169.254.170.2" // not constant to allow for swapping during unit-testing
|
||||||
)
|
)
|
||||||
|
|
||||||
// resolveCredentials extracts a credential provider from slice of config sources.
|
// resolveCredentials extracts a credential provider from slice of config
|
||||||
|
// sources.
|
||||||
//
|
//
|
||||||
// If an explict credential provider is not found the resolver will fallback to resolving
|
// If an explicit credential provider is not found the resolver will fallback
|
||||||
// credentials by extracting a credential provider from EnvConfig and SharedConfig.
|
// to resolving credentials by extracting a credential provider from EnvConfig
|
||||||
|
// and SharedConfig.
|
||||||
func resolveCredentials(ctx context.Context, cfg *aws.Config, configs configs) error {
|
func resolveCredentials(ctx context.Context, cfg *aws.Config, configs configs) error {
|
||||||
found, err := resolveCredentialProvider(ctx, cfg, configs)
|
found, err := resolveCredentialProvider(ctx, cfg, configs)
|
||||||
if err != nil {
|
if found || err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
if found {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err = resolveCredentialChain(ctx, cfg, configs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return resolveCredentialChain(ctx, cfg, configs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveCredentialProvider extracts the first instance of Credentials from the
|
// resolveCredentialProvider extracts the first instance of Credentials from the
|
||||||
|
|
@ -61,12 +56,9 @@ func resolveCredentials(ctx context.Context, cfg *aws.Config, configs configs) e
|
||||||
// * credentialsProviderProvider
|
// * credentialsProviderProvider
|
||||||
func resolveCredentialProvider(ctx context.Context, cfg *aws.Config, configs configs) (bool, error) {
|
func resolveCredentialProvider(ctx context.Context, cfg *aws.Config, configs configs) (bool, error) {
|
||||||
credProvider, found, err := getCredentialsProvider(ctx, configs)
|
credProvider, found, err := getCredentialsProvider(ctx, configs)
|
||||||
if err != nil {
|
if !found || err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if !found {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.Credentials, err = wrapWithCredentialsCache(ctx, configs, credProvider)
|
cfg.Credentials, err = wrapWithCredentialsCache(ctx, configs, credProvider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -180,7 +172,30 @@ func resolveSSOCredentials(ctx context.Context, cfg *aws.Config, sharedConfig *S
|
||||||
}
|
}
|
||||||
|
|
||||||
cfgCopy := cfg.Copy()
|
cfgCopy := cfg.Copy()
|
||||||
cfgCopy.Region = sharedConfig.SSORegion
|
|
||||||
|
if sharedConfig.SSOSession != nil {
|
||||||
|
ssoTokenProviderOptionsFn, found, err := getSSOTokenProviderOptions(ctx, configs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get SSOTokenProviderOptions from config sources, %w", err)
|
||||||
|
}
|
||||||
|
var optFns []func(*ssocreds.SSOTokenProviderOptions)
|
||||||
|
if found {
|
||||||
|
optFns = append(optFns, ssoTokenProviderOptionsFn)
|
||||||
|
}
|
||||||
|
cfgCopy.Region = sharedConfig.SSOSession.SSORegion
|
||||||
|
cachedPath, err := ssocreds.StandardCachedTokenFilepath(sharedConfig.SSOSession.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
oidcClient := ssooidc.NewFromConfig(cfgCopy)
|
||||||
|
tokenProvider := ssocreds.NewSSOTokenProvider(oidcClient, cachedPath, optFns...)
|
||||||
|
options = append(options, func(o *ssocreds.Options) {
|
||||||
|
o.SSOTokenProvider = tokenProvider
|
||||||
|
o.CachedTokenFilepath = cachedPath
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
cfgCopy.Region = sharedConfig.SSORegion
|
||||||
|
}
|
||||||
|
|
||||||
cfg.Credentials = ssocreds.New(sso.NewFromConfig(cfgCopy), sharedConfig.SSOAccountID, sharedConfig.SSORoleName, sharedConfig.SSOStartURL, options...)
|
cfg.Credentials = ssocreds.New(sso.NewFromConfig(cfgCopy), sharedConfig.SSOAccountID, sharedConfig.SSORoleName, sharedConfig.SSOStartURL, options...)
|
||||||
|
|
||||||
|
|
@ -369,10 +384,6 @@ func assumeWebIdentity(ctx context.Context, cfg *aws.Config, filepath string, ro
|
||||||
return fmt.Errorf("token file path is not set")
|
return fmt.Errorf("token file path is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(roleARN) == 0 {
|
|
||||||
return fmt.Errorf("role ARN is not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
optFns := []func(*stscreds.WebIdentityRoleOptions){
|
optFns := []func(*stscreds.WebIdentityRoleOptions){
|
||||||
func(options *stscreds.WebIdentityRoleOptions) {
|
func(options *stscreds.WebIdentityRoleOptions) {
|
||||||
options.RoleSessionName = sessionName
|
options.RoleSessionName = sessionName
|
||||||
|
|
@ -383,11 +394,29 @@ func assumeWebIdentity(ctx context.Context, cfg *aws.Config, filepath string, ro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if found {
|
if found {
|
||||||
optFns = append(optFns, optFn)
|
optFns = append(optFns, optFn)
|
||||||
}
|
}
|
||||||
|
|
||||||
provider := stscreds.NewWebIdentityRoleProvider(sts.NewFromConfig(*cfg), roleARN, stscreds.IdentityTokenFile(filepath), optFns...)
|
opts := stscreds.WebIdentityRoleOptions{
|
||||||
|
RoleARN: roleARN,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fn := range optFns {
|
||||||
|
fn(&opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts.RoleARN) == 0 {
|
||||||
|
return fmt.Errorf("role ARN is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := opts.Client
|
||||||
|
if client == nil {
|
||||||
|
client = sts.NewFromConfig(*cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := stscreds.NewWebIdentityRoleProvider(client, roleARN, stscreds.IdentityTokenFile(filepath), optFns...)
|
||||||
|
|
||||||
cfg.Credentials = provider
|
cfg.Credentials = provider
|
||||||
|
|
||||||
|
|
@ -454,7 +483,7 @@ func wrapWithCredentialsCache(
|
||||||
return provider, nil
|
return provider, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
credCacheOptions, found, err := getCredentialsCacheOptionsProvider(ctx, cfgs)
|
credCacheOptions, optionsFound, err := getCredentialsCacheOptionsProvider(ctx, cfgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -462,7 +491,7 @@ func wrapWithCredentialsCache(
|
||||||
// force allocation of a new slice if the additional options are
|
// force allocation of a new slice if the additional options are
|
||||||
// needed, to prevent overwriting the passed in slice of options.
|
// needed, to prevent overwriting the passed in slice of options.
|
||||||
optFns = optFns[:len(optFns):len(optFns)]
|
optFns = optFns[:len(optFns):len(optFns)]
|
||||||
if found {
|
if optionsFound {
|
||||||
optFns = append(optFns, credCacheOptions)
|
optFns = append(optFns, credCacheOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,19 @@ import (
|
||||||
"github.com/aws/aws-sdk-go-v2/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||||
"github.com/aws/aws-sdk-go-v2/internal/ini"
|
"github.com/aws/aws-sdk-go-v2/internal/ini"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/internal/shareddefaults"
|
||||||
"github.com/aws/smithy-go/logging"
|
"github.com/aws/smithy-go/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Prefix to use for filtering profiles
|
// Prefix to use for filtering profiles. The profile prefix should only
|
||||||
|
// exist in the shared config file, not the credentials file.
|
||||||
profilePrefix = `profile `
|
profilePrefix = `profile `
|
||||||
|
|
||||||
|
// Prefix to be used for SSO sections. These are supposed to only exist in
|
||||||
|
// the shared config file, not the credentials file.
|
||||||
|
ssoSectionPrefix = `sso-session `
|
||||||
|
|
||||||
// string equivalent for boolean
|
// string equivalent for boolean
|
||||||
endpointDiscoveryDisabled = `false`
|
endpointDiscoveryDisabled = `false`
|
||||||
endpointDiscoveryEnabled = `true`
|
endpointDiscoveryEnabled = `true`
|
||||||
|
|
@ -42,10 +48,13 @@ const (
|
||||||
roleDurationSecondsKey = "duration_seconds" // optional
|
roleDurationSecondsKey = "duration_seconds" // optional
|
||||||
|
|
||||||
// AWS Single Sign-On (AWS SSO) group
|
// AWS Single Sign-On (AWS SSO) group
|
||||||
|
ssoSessionNameKey = "sso_session"
|
||||||
|
|
||||||
|
ssoRegionKey = "sso_region"
|
||||||
|
ssoStartURLKey = "sso_start_url"
|
||||||
|
|
||||||
ssoAccountIDKey = "sso_account_id"
|
ssoAccountIDKey = "sso_account_id"
|
||||||
ssoRegionKey = "sso_region"
|
|
||||||
ssoRoleNameKey = "sso_role_name"
|
ssoRoleNameKey = "sso_role_name"
|
||||||
ssoStartURL = "sso_start_url"
|
|
||||||
|
|
||||||
// Additional Config fields
|
// Additional Config fields
|
||||||
regionKey = `region`
|
regionKey = `region`
|
||||||
|
|
@ -99,7 +108,7 @@ var defaultSharedConfigProfile = DefaultSharedConfigProfile
|
||||||
// - Linux/Unix: $HOME/.aws/credentials
|
// - Linux/Unix: $HOME/.aws/credentials
|
||||||
// - Windows: %USERPROFILE%\.aws\credentials
|
// - Windows: %USERPROFILE%\.aws\credentials
|
||||||
func DefaultSharedCredentialsFilename() string {
|
func DefaultSharedCredentialsFilename() string {
|
||||||
return filepath.Join(userHomeDir(), ".aws", "credentials")
|
return filepath.Join(shareddefaults.UserHomeDir(), ".aws", "credentials")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultSharedConfigFilename returns the SDK's default file path for
|
// DefaultSharedConfigFilename returns the SDK's default file path for
|
||||||
|
|
@ -110,7 +119,7 @@ func DefaultSharedCredentialsFilename() string {
|
||||||
// - Linux/Unix: $HOME/.aws/config
|
// - Linux/Unix: $HOME/.aws/config
|
||||||
// - Windows: %USERPROFILE%\.aws\config
|
// - Windows: %USERPROFILE%\.aws\config
|
||||||
func DefaultSharedConfigFilename() string {
|
func DefaultSharedConfigFilename() string {
|
||||||
return filepath.Join(userHomeDir(), ".aws", "config")
|
return filepath.Join(shareddefaults.UserHomeDir(), ".aws", "config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultSharedConfigFiles is a slice of the default shared config files that
|
// DefaultSharedConfigFiles is a slice of the default shared config files that
|
||||||
|
|
@ -119,12 +128,26 @@ var DefaultSharedConfigFiles = []string{
|
||||||
DefaultSharedConfigFilename(),
|
DefaultSharedConfigFilename(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultSharedCredentialsFiles is a slice of the default shared credentials files that
|
// DefaultSharedCredentialsFiles is a slice of the default shared credentials
|
||||||
// the will be used in order to load the SharedConfig.
|
// files that the will be used in order to load the SharedConfig.
|
||||||
var DefaultSharedCredentialsFiles = []string{
|
var DefaultSharedCredentialsFiles = []string{
|
||||||
DefaultSharedCredentialsFilename(),
|
DefaultSharedCredentialsFilename(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SSOSession provides the shared configuration parameters of the sso-session
|
||||||
|
// section.
|
||||||
|
type SSOSession struct {
|
||||||
|
Name string
|
||||||
|
SSORegion string
|
||||||
|
SSOStartURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SSOSession) setFromIniSection(section ini.Section) {
|
||||||
|
updateString(&s.Name, section, ssoSessionNameKey)
|
||||||
|
updateString(&s.SSORegion, section, ssoRegionKey)
|
||||||
|
updateString(&s.SSOStartURL, section, ssoStartURLKey)
|
||||||
|
}
|
||||||
|
|
||||||
// SharedConfig represents the configuration fields of the SDK config files.
|
// SharedConfig represents the configuration fields of the SDK config files.
|
||||||
type SharedConfig struct {
|
type SharedConfig struct {
|
||||||
Profile string
|
Profile string
|
||||||
|
|
@ -144,10 +167,17 @@ type SharedConfig struct {
|
||||||
CredentialProcess string
|
CredentialProcess string
|
||||||
WebIdentityTokenFile string
|
WebIdentityTokenFile string
|
||||||
|
|
||||||
|
// SSO session options
|
||||||
|
SSOSessionName string
|
||||||
|
SSOSession *SSOSession
|
||||||
|
|
||||||
|
// Legacy SSO session options
|
||||||
|
SSORegion string
|
||||||
|
SSOStartURL string
|
||||||
|
|
||||||
|
// SSO fields not used
|
||||||
SSOAccountID string
|
SSOAccountID string
|
||||||
SSORegion string
|
|
||||||
SSORoleName string
|
SSORoleName string
|
||||||
SSOStartURL string
|
|
||||||
|
|
||||||
RoleARN string
|
RoleARN string
|
||||||
ExternalID string
|
ExternalID string
|
||||||
|
|
@ -463,7 +493,6 @@ type LoadSharedConfigOptions struct {
|
||||||
//
|
//
|
||||||
// You can read more about shared config and credentials file location at
|
// You can read more about shared config and credentials file location at
|
||||||
// https://docs.aws.amazon.com/credref/latest/refdocs/file-location.html#file-location
|
// https://docs.aws.amazon.com/credref/latest/refdocs/file-location.html#file-location
|
||||||
//
|
|
||||||
func LoadSharedConfigProfile(ctx context.Context, profile string, optFns ...func(*LoadSharedConfigOptions)) (SharedConfig, error) {
|
func LoadSharedConfigProfile(ctx context.Context, profile string, optFns ...func(*LoadSharedConfigOptions)) (SharedConfig, error) {
|
||||||
var option LoadSharedConfigOptions
|
var option LoadSharedConfigOptions
|
||||||
for _, fn := range optFns {
|
for _, fn := range optFns {
|
||||||
|
|
@ -485,7 +514,7 @@ func LoadSharedConfigProfile(ctx context.Context, profile string, optFns ...func
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for profile prefix and drop duplicates or invalid profiles
|
// check for profile prefix and drop duplicates or invalid profiles
|
||||||
err = processConfigSections(ctx, configSections, option.Logger)
|
err = processConfigSections(ctx, &configSections, option.Logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return SharedConfig{}, err
|
return SharedConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -497,12 +526,12 @@ func LoadSharedConfigProfile(ctx context.Context, profile string, optFns ...func
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for profile prefix and drop duplicates or invalid profiles
|
// check for profile prefix and drop duplicates or invalid profiles
|
||||||
err = processCredentialsSections(ctx, credentialsSections, option.Logger)
|
err = processCredentialsSections(ctx, &credentialsSections, option.Logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return SharedConfig{}, err
|
return SharedConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mergeSections(configSections, credentialsSections)
|
err = mergeSections(&configSections, credentialsSections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return SharedConfig{}, err
|
return SharedConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -516,53 +545,73 @@ func LoadSharedConfigProfile(ctx context.Context, profile string, optFns ...func
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func processConfigSections(ctx context.Context, sections ini.Sections, logger logging.Logger) error {
|
func processConfigSections(ctx context.Context, sections *ini.Sections, logger logging.Logger) error {
|
||||||
|
skipSections := map[string]struct{}{}
|
||||||
|
|
||||||
for _, section := range sections.List() {
|
for _, section := range sections.List() {
|
||||||
// drop profiles without prefix for config files
|
if _, ok := skipSections[section]; ok {
|
||||||
if !strings.HasPrefix(section, profilePrefix) && !strings.EqualFold(section, "default") {
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop sections from config file that do not have expected prefixes.
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(section, profilePrefix):
|
||||||
|
// Rename sections to remove "profile " prefixing to match with
|
||||||
|
// credentials file. If default is already present, it will be
|
||||||
|
// dropped.
|
||||||
|
newName, err := renameProfileSection(section, sections, logger)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to rename profile section, %w", err)
|
||||||
|
}
|
||||||
|
skipSections[newName] = struct{}{}
|
||||||
|
|
||||||
|
case strings.HasPrefix(section, ssoSectionPrefix):
|
||||||
|
case strings.EqualFold(section, "default"):
|
||||||
|
default:
|
||||||
// drop this section, as invalid profile name
|
// drop this section, as invalid profile name
|
||||||
sections.DeleteSection(section)
|
sections.DeleteSection(section)
|
||||||
|
|
||||||
if logger != nil {
|
if logger != nil {
|
||||||
logger.Logf(logging.Debug,
|
logger.Logf(logging.Debug, "A profile defined with name `%v` is ignored. "+
|
||||||
"A profile defined with name `%v` is ignored. For use within a shared configuration file, "+
|
"For use within a shared configuration file, "+
|
||||||
"a non-default profile must have `profile ` prefixed to the profile name.\n",
|
"a non-default profile must have `profile ` "+
|
||||||
|
"prefixed to the profile name.",
|
||||||
section,
|
section,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rename sections to remove `profile ` prefixing to match with credentials file.
|
|
||||||
// if default is already present, it will be dropped.
|
|
||||||
for _, section := range sections.List() {
|
|
||||||
if strings.HasPrefix(section, profilePrefix) {
|
|
||||||
v, ok := sections.GetSection(section)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("error processing profiles within the shared configuration files")
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete section with profile as prefix
|
|
||||||
sections.DeleteSection(section)
|
|
||||||
|
|
||||||
// set the value to non-prefixed name in sections.
|
|
||||||
section = strings.TrimPrefix(section, profilePrefix)
|
|
||||||
if sections.HasSection(section) {
|
|
||||||
oldSection, _ := sections.GetSection(section)
|
|
||||||
v.Logs = append(v.Logs,
|
|
||||||
fmt.Sprintf("A default profile prefixed with `profile ` found in %s, "+
|
|
||||||
"overrided non-prefixed default profile from %s", v.SourceFile, oldSection.SourceFile))
|
|
||||||
}
|
|
||||||
|
|
||||||
// assign non-prefixed name to section
|
|
||||||
v.Name = section
|
|
||||||
sections.SetSection(section, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func processCredentialsSections(ctx context.Context, sections ini.Sections, logger logging.Logger) error {
|
func renameProfileSection(section string, sections *ini.Sections, logger logging.Logger) (string, error) {
|
||||||
|
v, ok := sections.GetSection(section)
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("error processing profiles within the shared configuration files")
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete section with profile as prefix
|
||||||
|
sections.DeleteSection(section)
|
||||||
|
|
||||||
|
// set the value to non-prefixed name in sections.
|
||||||
|
section = strings.TrimPrefix(section, profilePrefix)
|
||||||
|
if sections.HasSection(section) {
|
||||||
|
oldSection, _ := sections.GetSection(section)
|
||||||
|
v.Logs = append(v.Logs,
|
||||||
|
fmt.Sprintf("A non-default profile not prefixed with `profile ` found in %s, "+
|
||||||
|
"overriding non-default profile from %s",
|
||||||
|
v.SourceFile, oldSection.SourceFile))
|
||||||
|
sections.DeleteSection(section)
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign non-prefixed name to section
|
||||||
|
v.Name = section
|
||||||
|
sections.SetSection(section, v)
|
||||||
|
|
||||||
|
return section, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processCredentialsSections(ctx context.Context, sections *ini.Sections, logger logging.Logger) error {
|
||||||
for _, section := range sections.List() {
|
for _, section := range sections.List() {
|
||||||
// drop profiles with prefix for credential files
|
// drop profiles with prefix for credential files
|
||||||
if strings.HasPrefix(section, profilePrefix) {
|
if strings.HasPrefix(section, profilePrefix) {
|
||||||
|
|
@ -596,7 +645,7 @@ func loadIniFiles(filenames []string) (ini.Sections, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// mergeSections into mergedSections
|
// mergeSections into mergedSections
|
||||||
err = mergeSections(mergedSections, sections)
|
err = mergeSections(&mergedSections, sections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ini.Sections{}, SharedConfigLoadError{Filename: filename, Err: err}
|
return ini.Sections{}, SharedConfigLoadError{Filename: filename, Err: err}
|
||||||
}
|
}
|
||||||
|
|
@ -606,7 +655,7 @@ func loadIniFiles(filenames []string) (ini.Sections, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// mergeSections merges source section properties into destination section properties
|
// mergeSections merges source section properties into destination section properties
|
||||||
func mergeSections(dst, src ini.Sections) error {
|
func mergeSections(dst *ini.Sections, src ini.Sections) error {
|
||||||
for _, sectionName := range src.List() {
|
for _, sectionName := range src.List() {
|
||||||
srcSection, _ := src.GetSection(sectionName)
|
srcSection, _ := src.GetSection(sectionName)
|
||||||
|
|
||||||
|
|
@ -680,6 +729,13 @@ func mergeSections(dst, src ini.Sections) error {
|
||||||
useFIPSEndpointKey,
|
useFIPSEndpointKey,
|
||||||
defaultsModeKey,
|
defaultsModeKey,
|
||||||
retryModeKey,
|
retryModeKey,
|
||||||
|
caBundleKey,
|
||||||
|
|
||||||
|
ssoSessionNameKey,
|
||||||
|
ssoAccountIDKey,
|
||||||
|
ssoRegionKey,
|
||||||
|
ssoRoleNameKey,
|
||||||
|
ssoStartURLKey,
|
||||||
}
|
}
|
||||||
for i := range stringKeys {
|
for i := range stringKeys {
|
||||||
if err := mergeStringKey(&srcSection, &dstSection, sectionName, stringKeys[i]); err != nil {
|
if err := mergeStringKey(&srcSection, &dstSection, sectionName, stringKeys[i]); err != nil {
|
||||||
|
|
@ -698,7 +754,7 @@ func mergeSections(dst, src ini.Sections) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set srcSection on dst srcSection
|
// set srcSection on dst srcSection
|
||||||
dst = dst.SetSection(sectionName, dstSection)
|
*dst = dst.SetSection(sectionName, dstSection)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -769,7 +825,7 @@ func (c *SharedConfig) setFromIniSections(profiles map[string]struct{}, profile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set config from the provided ini section
|
// set config from the provided INI section
|
||||||
err := c.setFromIniSection(profile, section)
|
err := c.setFromIniSection(profile, section)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error fetching config from profile, %v, %w", profile, err)
|
return fmt.Errorf("error fetching config from profile, %v, %w", profile, err)
|
||||||
|
|
@ -782,9 +838,8 @@ func (c *SharedConfig) setFromIniSections(profiles map[string]struct{}, profile
|
||||||
// profile only have credential provider options.
|
// profile only have credential provider options.
|
||||||
c.clearAssumeRoleOptions()
|
c.clearAssumeRoleOptions()
|
||||||
} else {
|
} else {
|
||||||
// First time a profile has been seen, It must either be a assume role
|
// First time a profile has been seen. Assert if the credential type
|
||||||
// credentials, or SSO. Assert if the credential type requires a role ARN,
|
// requires a role ARN, the ARN is also set
|
||||||
// the ARN is also set, or validate that the SSO configuration is complete.
|
|
||||||
if err := c.validateCredentialsConfig(profile); err != nil {
|
if err := c.validateCredentialsConfig(profile); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -832,11 +887,26 @@ func (c *SharedConfig) setFromIniSections(profiles map[string]struct{}, profile
|
||||||
c.Source = srcCfg
|
c.Source = srcCfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the profile contains an SSO session parameter, the session MUST exist
|
||||||
|
// as a section in the config file. Load the SSO session using the name
|
||||||
|
// provided. If the session section is not found or incomplete an error
|
||||||
|
// will be returned.
|
||||||
|
if c.hasSSOTokenProviderConfiguration() {
|
||||||
|
section, ok := sections.GetSection(ssoSectionPrefix + strings.TrimSpace(c.SSOSessionName))
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("failed to find SSO session section, %v", c.SSOSessionName)
|
||||||
|
}
|
||||||
|
var ssoSession SSOSession
|
||||||
|
ssoSession.setFromIniSection(section)
|
||||||
|
ssoSession.Name = c.SSOSessionName
|
||||||
|
c.SSOSession = &ssoSession
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setFromIniSection loads the configuration from the profile section defined in
|
// setFromIniSection loads the configuration from the profile section defined in
|
||||||
// the provided ini file. A SharedConfig pointer type value is used so that
|
// the provided INI file. A SharedConfig pointer type value is used so that
|
||||||
// multiple config file loadings can be chained.
|
// multiple config file loadings can be chained.
|
||||||
//
|
//
|
||||||
// Only loads complete logically grouped values, and will not set fields in cfg
|
// Only loads complete logically grouped values, and will not set fields in cfg
|
||||||
|
|
@ -871,10 +941,16 @@ func (c *SharedConfig) setFromIniSection(profile string, section ini.Section) er
|
||||||
updateString(&c.Region, section, regionKey)
|
updateString(&c.Region, section, regionKey)
|
||||||
|
|
||||||
// AWS Single Sign-On (AWS SSO)
|
// AWS Single Sign-On (AWS SSO)
|
||||||
updateString(&c.SSOAccountID, section, ssoAccountIDKey)
|
// SSO session options
|
||||||
|
updateString(&c.SSOSessionName, section, ssoSessionNameKey)
|
||||||
|
|
||||||
|
// Legacy SSO session options
|
||||||
updateString(&c.SSORegion, section, ssoRegionKey)
|
updateString(&c.SSORegion, section, ssoRegionKey)
|
||||||
|
updateString(&c.SSOStartURL, section, ssoStartURLKey)
|
||||||
|
|
||||||
|
// SSO fields not used
|
||||||
|
updateString(&c.SSOAccountID, section, ssoAccountIDKey)
|
||||||
updateString(&c.SSORoleName, section, ssoRoleNameKey)
|
updateString(&c.SSORoleName, section, ssoRoleNameKey)
|
||||||
updateString(&c.SSOStartURL, section, ssoStartURL)
|
|
||||||
|
|
||||||
if section.Has(roleDurationSecondsKey) {
|
if section.Has(roleDurationSecondsKey) {
|
||||||
d := time.Duration(section.Int(roleDurationSecondsKey)) * time.Second
|
d := time.Duration(section.Int(roleDurationSecondsKey)) * time.Second
|
||||||
|
|
@ -992,32 +1068,47 @@ func (c *SharedConfig) validateCredentialType() error {
|
||||||
len(c.CredentialProcess) != 0,
|
len(c.CredentialProcess) != 0,
|
||||||
len(c.WebIdentityTokenFile) != 0,
|
len(c.WebIdentityTokenFile) != 0,
|
||||||
) {
|
) {
|
||||||
return fmt.Errorf("only one credential type may be specified per profile: source profile, credential source, credential process, web identity token, or sso")
|
return fmt.Errorf("only one credential type may be specified per profile: source profile, credential source, credential process, web identity token")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SharedConfig) validateSSOConfiguration() error {
|
func (c *SharedConfig) validateSSOConfiguration() error {
|
||||||
if !c.hasSSOConfiguration() {
|
if c.hasSSOTokenProviderConfiguration() {
|
||||||
|
err := c.validateSSOTokenProviderConfiguration()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.hasLegacySSOConfiguration() {
|
||||||
|
err := c.validateLegacySSOConfiguration()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SharedConfig) validateSSOTokenProviderConfiguration() error {
|
||||||
var missing []string
|
var missing []string
|
||||||
if len(c.SSOAccountID) == 0 {
|
|
||||||
missing = append(missing, ssoAccountIDKey)
|
if len(c.SSOSessionName) == 0 {
|
||||||
|
missing = append(missing, ssoSessionNameKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.SSORegion) == 0 {
|
if c.SSOSession == nil {
|
||||||
missing = append(missing, ssoRegionKey)
|
missing = append(missing, ssoSectionPrefix)
|
||||||
}
|
} else {
|
||||||
|
if len(c.SSOSession.SSORegion) == 0 {
|
||||||
|
missing = append(missing, ssoRegionKey)
|
||||||
|
}
|
||||||
|
|
||||||
if len(c.SSORoleName) == 0 {
|
if len(c.SSOSession.SSOStartURL) == 0 {
|
||||||
missing = append(missing, ssoRoleNameKey)
|
missing = append(missing, ssoStartURLKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.SSOStartURL) == 0 {
|
|
||||||
missing = append(missing, ssoStartURL)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(missing) > 0 {
|
if len(missing) > 0 {
|
||||||
|
|
@ -1025,6 +1116,40 @@ func (c *SharedConfig) validateSSOConfiguration() error {
|
||||||
c.Profile, strings.Join(missing, ", "))
|
c.Profile, strings.Join(missing, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(c.SSORegion) > 0 && c.SSORegion != c.SSOSession.SSORegion {
|
||||||
|
return fmt.Errorf("%s in profile %q must match %s in %s", ssoRegionKey, c.Profile, ssoRegionKey, ssoSectionPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.SSOStartURL) > 0 && c.SSOStartURL != c.SSOSession.SSOStartURL {
|
||||||
|
return fmt.Errorf("%s in profile %q must match %s in %s", ssoStartURLKey, c.Profile, ssoStartURLKey, ssoSectionPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SharedConfig) validateLegacySSOConfiguration() error {
|
||||||
|
var missing []string
|
||||||
|
|
||||||
|
if len(c.SSORegion) == 0 {
|
||||||
|
missing = append(missing, ssoRegionKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.SSOStartURL) == 0 {
|
||||||
|
missing = append(missing, ssoStartURLKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.SSOAccountID) == 0 {
|
||||||
|
missing = append(missing, ssoAccountIDKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.SSORoleName) == 0 {
|
||||||
|
missing = append(missing, ssoRoleNameKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missing) > 0 {
|
||||||
|
return fmt.Errorf("profile %q is configured to use SSO but is missing required configuration: %s",
|
||||||
|
c.Profile, strings.Join(missing, ", "))
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1044,15 +1169,15 @@ func (c *SharedConfig) hasCredentials() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SharedConfig) hasSSOConfiguration() bool {
|
func (c *SharedConfig) hasSSOConfiguration() bool {
|
||||||
switch {
|
return c.hasSSOTokenProviderConfiguration() || c.hasLegacySSOConfiguration()
|
||||||
case len(c.SSOAccountID) != 0:
|
}
|
||||||
case len(c.SSORegion) != 0:
|
|
||||||
case len(c.SSORoleName) != 0:
|
func (c *SharedConfig) hasSSOTokenProviderConfiguration() bool {
|
||||||
case len(c.SSOStartURL) != 0:
|
return len(c.SSOSessionName) > 0
|
||||||
default:
|
}
|
||||||
return false
|
|
||||||
}
|
func (c *SharedConfig) hasLegacySSOConfiguration() bool {
|
||||||
return true
|
return len(c.SSORegion) > 0 || len(c.SSOAccountID) > 0 || len(c.SSOStartURL) > 0 || len(c.SSORoleName) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SharedConfig) clearAssumeRoleOptions() {
|
func (c *SharedConfig) clearAssumeRoleOptions() {
|
||||||
|
|
@ -1143,12 +1268,6 @@ func (e CredentialRequiresARNError) Error() string {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func userHomeDir() string {
|
|
||||||
// Ignore errors since we only care about Windows and *nix.
|
|
||||||
homedir, _ := os.UserHomeDir()
|
|
||||||
return homedir
|
|
||||||
}
|
|
||||||
|
|
||||||
func oneOrNone(bs ...bool) bool {
|
func oneOrNone(bs ...bool) bool {
|
||||||
var count int
|
var count int
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,201 @@
|
||||||
|
# v1.13.24 (2023-05-09)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.13.23 (2023-05-08)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.22 (2023-05-04)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.21 (2023-04-24)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.20 (2023-04-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.19 (2023-04-07)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.18 (2023-03-21)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.17 (2023-03-14)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.16 (2023-03-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.15 (2023-02-22)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.14 (2023-02-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.13 (2023-02-15)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.12 (2023-02-03)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.11 (2023-02-01)
|
||||||
|
|
||||||
|
* No change notes available for this release.
|
||||||
|
|
||||||
|
# v1.13.10 (2023-01-25)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.9 (2023-01-23)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.8 (2023-01-05)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.7 (2022-12-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.6 (2022-12-19)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.5 (2022-12-15)
|
||||||
|
|
||||||
|
* **Bug Fix**: Unify logic between shared config and in finding home directory
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.4 (2022-12-02)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.3 (2022-11-22)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.2 (2022-11-17)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.1 (2022-11-16)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.0 (2022-11-11)
|
||||||
|
|
||||||
|
* **Announcement**: When using the SSOTokenProvider, a previous implementation incorrectly compensated for invalid SSOTokenProvider configurations in the shared profile. This has been fixed via PR #1903 and tracked in issue #1846
|
||||||
|
* **Feature**: Adds token refresh support (via SSOTokenProvider) when using the SSOCredentialProvider
|
||||||
|
|
||||||
|
# v1.12.24 (2022-11-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.23 (2022-10-24)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.22 (2022-10-21)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.21 (2022-09-30)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.20 (2022-09-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.19 (2022-09-14)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.18 (2022-09-02)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.17 (2022-08-31)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.16 (2022-08-30)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.15 (2022-08-29)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.14 (2022-08-15)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.13 (2022-08-11)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.12 (2022-08-09)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.11 (2022-08-08)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.10 (2022-08-01)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.9 (2022-07-11)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.8 (2022-07-05)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.7 (2022-06-29)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.6 (2022-06-16)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.5 (2022-06-07)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.4 (2022-05-26)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.3 (2022-05-25)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.2 (2022-05-17)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.1 (2022-05-16)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
# v1.12.0 (2022-04-25)
|
# v1.12.0 (2022-04-25)
|
||||||
|
|
||||||
* **Feature**: Adds Duration and Policy options that can be used when creating stscreds.WebIdentityRoleProvider credentials provider.
|
* **Feature**: Adds Duration and Policy options that can be used when creating stscreds.WebIdentityRoleProvider credentials provider.
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,27 @@
|
||||||
// Package ec2rolecreds provides the credentials provider implementation for
|
// Package ec2rolecreds provides the credentials provider implementation for
|
||||||
// retrieving AWS credentials from Amazon EC2 Instance Roles via Amazon EC2 IMDS.
|
// retrieving AWS credentials from Amazon EC2 Instance Roles via Amazon EC2 IMDS.
|
||||||
//
|
//
|
||||||
// Concurrency and caching
|
// # Concurrency and caching
|
||||||
//
|
//
|
||||||
// The Provider is not safe to be used concurrently, and does not provide any
|
// The Provider is not safe to be used concurrently, and does not provide any
|
||||||
// caching of credentials retrieved. You should wrap the Provider with a
|
// caching of credentials retrieved. You should wrap the Provider with a
|
||||||
// `aws.CredentialsCache` to provide concurrency safety, and caching of
|
// `aws.CredentialsCache` to provide concurrency safety, and caching of
|
||||||
// credentials.
|
// credentials.
|
||||||
//
|
//
|
||||||
// Loading credentials with the SDK's AWS Config
|
// # Loading credentials with the SDK's AWS Config
|
||||||
//
|
//
|
||||||
// The EC2 Instance role credentials provider will automatically be the resolved
|
// The EC2 Instance role credentials provider will automatically be the resolved
|
||||||
// credential provider int he credential chain if no other credential provider is
|
// credential provider in the credential chain if no other credential provider is
|
||||||
// resolved first.
|
// resolved first.
|
||||||
//
|
//
|
||||||
// To explicitly instruct the SDK's credentials resolving to use the EC2 Instance
|
// To explicitly instruct the SDK's credentials resolving to use the EC2 Instance
|
||||||
// role for credentials, you specify a `credentials_source` property in the config
|
// role for credentials, you specify a `credentials_source` property in the config
|
||||||
// profile the SDK will load.
|
// profile the SDK will load.
|
||||||
//
|
//
|
||||||
// [default]
|
// [default]
|
||||||
// credential_source = Ec2InstanceMetadata
|
// credential_source = Ec2InstanceMetadata
|
||||||
//
|
//
|
||||||
// Loading credentials with the Provider directly
|
// # Loading credentials with the Provider directly
|
||||||
//
|
//
|
||||||
// Another way to use the EC2 Instance role credentials provider is to create it
|
// Another way to use the EC2 Instance role credentials provider is to create it
|
||||||
// directly and assign it as the credentials provider for an API client.
|
// directly and assign it as the credentials provider for an API client.
|
||||||
|
|
@ -30,28 +30,28 @@
|
||||||
// it with the CredentialsCache before assigning the provider to the Amazon S3 API
|
// it with the CredentialsCache before assigning the provider to the Amazon S3 API
|
||||||
// client's Credentials option.
|
// client's Credentials option.
|
||||||
//
|
//
|
||||||
// provider := imds.New(imds.Options{})
|
// provider := imds.New(imds.Options{})
|
||||||
//
|
//
|
||||||
// // Create the service client value configured for credentials.
|
// // Create the service client value configured for credentials.
|
||||||
// svc := s3.New(s3.Options{
|
// svc := s3.New(s3.Options{
|
||||||
// Credentials: aws.NewCredentialsCache(provider),
|
// Credentials: aws.NewCredentialsCache(provider),
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// If you need more control, you can set the configuration options on the
|
// If you need more control, you can set the configuration options on the
|
||||||
// credentials provider using the imds.Options type to configure the EC2 IMDS
|
// credentials provider using the imds.Options type to configure the EC2 IMDS
|
||||||
// API Client and ExpiryWindow of the retrieved credentials.
|
// API Client and ExpiryWindow of the retrieved credentials.
|
||||||
//
|
//
|
||||||
// provider := imds.New(imds.Options{
|
// provider := imds.New(imds.Options{
|
||||||
// // See imds.Options type's documentation for more options available.
|
// // See imds.Options type's documentation for more options available.
|
||||||
// Client: imds.New(Options{
|
// Client: imds.New(Options{
|
||||||
// HTTPClient: customHTTPClient,
|
// HTTPClient: customHTTPClient,
|
||||||
// }),
|
// }),
|
||||||
//
|
//
|
||||||
// // Modify how soon credentials expire prior to their original expiry time.
|
// // Modify how soon credentials expire prior to their original expiry time.
|
||||||
// ExpiryWindow: 5 * time.Minute,
|
// ExpiryWindow: 5 * time.Minute,
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// EC2 IMDS API Client
|
// # EC2 IMDS API Client
|
||||||
//
|
//
|
||||||
// See the github.com/aws/aws-sdk-go-v2/feature/ec2/imds module for more details on
|
// See the github.com/aws/aws-sdk-go-v2/feature/ec2/imds module for more details on
|
||||||
// configuring the client, and options available.
|
// configuring the client, and options available.
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ type GetMetadataAPIClient interface {
|
||||||
//
|
//
|
||||||
// The New function must be used to create the with a custom EC2 IMDS client.
|
// The New function must be used to create the with a custom EC2 IMDS client.
|
||||||
//
|
//
|
||||||
// p := &ec2rolecreds.New(func(o *ec2rolecreds.Options{
|
// p := &ec2rolecreds.New(func(o *ec2rolecreds.Options{
|
||||||
// o.Client = imds.New(imds.Options{/* custom options */})
|
// o.Client = imds.New(imds.Options{/* custom options */})
|
||||||
// })
|
// })
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
options Options
|
options Options
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,26 +7,29 @@
|
||||||
//
|
//
|
||||||
// Static credentials will never expire once they have been retrieved. The format
|
// Static credentials will never expire once they have been retrieved. The format
|
||||||
// of the static credentials response:
|
// of the static credentials response:
|
||||||
// {
|
//
|
||||||
// "AccessKeyId" : "MUA...",
|
// {
|
||||||
// "SecretAccessKey" : "/7PC5om....",
|
// "AccessKeyId" : "MUA...",
|
||||||
// }
|
// "SecretAccessKey" : "/7PC5om....",
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// Refreshable credentials will expire within the "ExpiryWindow" of the Expiration
|
// Refreshable credentials will expire within the "ExpiryWindow" of the Expiration
|
||||||
// value in the response. The format of the refreshable credentials response:
|
// value in the response. The format of the refreshable credentials response:
|
||||||
// {
|
//
|
||||||
// "AccessKeyId" : "MUA...",
|
// {
|
||||||
// "SecretAccessKey" : "/7PC5om....",
|
// "AccessKeyId" : "MUA...",
|
||||||
// "Token" : "AQoDY....=",
|
// "SecretAccessKey" : "/7PC5om....",
|
||||||
// "Expiration" : "2016-02-25T06:03:31Z"
|
// "Token" : "AQoDY....=",
|
||||||
// }
|
// "Expiration" : "2016-02-25T06:03:31Z"
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// Errors should be returned in the following format and only returned with 400
|
// Errors should be returned in the following format and only returned with 400
|
||||||
// or 500 HTTP status codes.
|
// or 500 HTTP status codes.
|
||||||
// {
|
//
|
||||||
// "code": "ErrorCode",
|
// {
|
||||||
// "message": "Helpful error message."
|
// "code": "ErrorCode",
|
||||||
// }
|
// "message": "Helpful error message."
|
||||||
|
// }
|
||||||
package endpointcreds
|
package endpointcreds
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,4 @@
|
||||||
package credentials
|
package credentials
|
||||||
|
|
||||||
// goModuleVersion is the tagged release for this module
|
// goModuleVersion is the tagged release for this module
|
||||||
const goModuleVersion = "1.12.0"
|
const goModuleVersion = "1.13.24"
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,14 @@
|
||||||
// option, you should make sure that the config file is as locked down as possible
|
// option, you should make sure that the config file is as locked down as possible
|
||||||
// using security best practices for your operating system.
|
// using security best practices for your operating system.
|
||||||
//
|
//
|
||||||
// Concurrency and caching
|
// # Concurrency and caching
|
||||||
//
|
//
|
||||||
// The Provider is not safe to be used concurrently, and does not provide any
|
// The Provider is not safe to be used concurrently, and does not provide any
|
||||||
// caching of credentials retrieved. You should wrap the Provider with a
|
// caching of credentials retrieved. You should wrap the Provider with a
|
||||||
// `aws.CredentialsCache` to provide concurrency safety, and caching of
|
// `aws.CredentialsCache` to provide concurrency safety, and caching of
|
||||||
// credentials.
|
// credentials.
|
||||||
//
|
//
|
||||||
// Loading credentials with the SDKs AWS Config
|
// # Loading credentials with the SDKs AWS Config
|
||||||
//
|
//
|
||||||
// You can use credentials from a AWS shared config `credential_process` in a
|
// You can use credentials from a AWS shared config `credential_process` in a
|
||||||
// variety of ways.
|
// variety of ways.
|
||||||
|
|
@ -24,20 +24,20 @@
|
||||||
// called. You also need to set the AWS_SDK_LOAD_CONFIG environment variable
|
// called. You also need to set the AWS_SDK_LOAD_CONFIG environment variable
|
||||||
// (e.g., `export AWS_SDK_LOAD_CONFIG=1`) to use the shared config file.
|
// (e.g., `export AWS_SDK_LOAD_CONFIG=1`) to use the shared config file.
|
||||||
//
|
//
|
||||||
// [default]
|
// [default]
|
||||||
// credential_process = /command/to/call
|
// credential_process = /command/to/call
|
||||||
//
|
//
|
||||||
// Loading configuration using external will use the credential process to
|
// Loading configuration using external will use the credential process to
|
||||||
// retrieve credentials. NOTE: If there are credentials in the profile you are
|
// retrieve credentials. NOTE: If there are credentials in the profile you are
|
||||||
// using, the credential process will not be used.
|
// using, the credential process will not be used.
|
||||||
//
|
//
|
||||||
// // Initialize a session to load credentials.
|
// // Initialize a session to load credentials.
|
||||||
// cfg, _ := config.LoadDefaultConfig(context.TODO())
|
// cfg, _ := config.LoadDefaultConfig(context.TODO())
|
||||||
//
|
//
|
||||||
// // Create S3 service client to use the credentials.
|
// // Create S3 service client to use the credentials.
|
||||||
// svc := s3.NewFromConfig(cfg)
|
// svc := s3.NewFromConfig(cfg)
|
||||||
//
|
//
|
||||||
// Loading credentials with the Provider directly
|
// # Loading credentials with the Provider directly
|
||||||
//
|
//
|
||||||
// Another way to use the credentials process provider is by using the
|
// Another way to use the credentials process provider is by using the
|
||||||
// `NewProvider` constructor to create the provider and providing a it with a
|
// `NewProvider` constructor to create the provider and providing a it with a
|
||||||
|
|
@ -47,46 +47,46 @@
|
||||||
// it with the CredentialsCache before assigning the provider to the Amazon S3 API
|
// it with the CredentialsCache before assigning the provider to the Amazon S3 API
|
||||||
// client's Credentials option.
|
// client's Credentials option.
|
||||||
//
|
//
|
||||||
// // Create credentials using the Provider.
|
// // Create credentials using the Provider.
|
||||||
// provider := processcreds.NewProvider("/path/to/command")
|
// provider := processcreds.NewProvider("/path/to/command")
|
||||||
//
|
//
|
||||||
// // Create the service client value configured for credentials.
|
// // Create the service client value configured for credentials.
|
||||||
// svc := s3.New(s3.Options{
|
// svc := s3.New(s3.Options{
|
||||||
// Credentials: aws.NewCredentialsCache(provider),
|
// Credentials: aws.NewCredentialsCache(provider),
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// If you need more control, you can set any configurable options in the
|
// If you need more control, you can set any configurable options in the
|
||||||
// credentials using one or more option functions.
|
// credentials using one or more option functions.
|
||||||
//
|
//
|
||||||
// provider := processcreds.NewProvider("/path/to/command",
|
// provider := processcreds.NewProvider("/path/to/command",
|
||||||
// func(o *processcreds.Options) {
|
// func(o *processcreds.Options) {
|
||||||
// // Override the provider's default timeout
|
// // Override the provider's default timeout
|
||||||
// o.Timeout = 2 * time.Minute
|
// o.Timeout = 2 * time.Minute
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// You can also use your own `exec.Cmd` value by satisfying a value that satisfies
|
// You can also use your own `exec.Cmd` value by satisfying a value that satisfies
|
||||||
// the `NewCommandBuilder` interface and use the `NewProviderCommand` constructor.
|
// the `NewCommandBuilder` interface and use the `NewProviderCommand` constructor.
|
||||||
//
|
//
|
||||||
// // Create an exec.Cmd
|
// // Create an exec.Cmd
|
||||||
// cmdBuilder := processcreds.NewCommandBuilderFunc(
|
// cmdBuilder := processcreds.NewCommandBuilderFunc(
|
||||||
// func(ctx context.Context) (*exec.Cmd, error) {
|
// func(ctx context.Context) (*exec.Cmd, error) {
|
||||||
// cmd := exec.CommandContext(ctx,
|
// cmd := exec.CommandContext(ctx,
|
||||||
// "customCLICommand",
|
// "customCLICommand",
|
||||||
// "-a", "argument",
|
// "-a", "argument",
|
||||||
// )
|
// )
|
||||||
// cmd.Env = []string{
|
// cmd.Env = []string{
|
||||||
// "ENV_VAR_FOO=value",
|
// "ENV_VAR_FOO=value",
|
||||||
// "ENV_VAR_BAR=other_value",
|
// "ENV_VAR_BAR=other_value",
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// return cmd, nil
|
// return cmd, nil
|
||||||
// },
|
// },
|
||||||
// )
|
// )
|
||||||
//
|
//
|
||||||
// // Create credentials using your exec.Cmd and custom timeout
|
// // Create credentials using your exec.Cmd and custom timeout
|
||||||
// provider := processcreds.NewProviderCommand(cmdBuilder,
|
// provider := processcreds.NewProviderCommand(cmdBuilder,
|
||||||
// func(opt *processcreds.Provider) {
|
// func(opt *processcreds.Provider) {
|
||||||
// // optionally override the provider's default timeout
|
// // optionally override the provider's default timeout
|
||||||
// opt.Timeout = 1 * time.Second
|
// opt.Timeout = 1 * time.Second
|
||||||
// })
|
// })
|
||||||
package processcreds
|
package processcreds
|
||||||
|
|
|
||||||
|
|
@ -149,12 +149,24 @@ func NewProviderCommand(builder NewCommandBuilder, options ...func(*Options)) *P
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
type credentialProcessResponse struct {
|
// A CredentialProcessResponse is the AWS credentials format that must be
|
||||||
Version int
|
// returned when executing an external credential_process.
|
||||||
AccessKeyID string `json:"AccessKeyId"`
|
type CredentialProcessResponse struct {
|
||||||
|
// As of this writing, the Version key must be set to 1. This might
|
||||||
|
// increment over time as the structure evolves.
|
||||||
|
Version int
|
||||||
|
|
||||||
|
// The access key ID that identifies the temporary security credentials.
|
||||||
|
AccessKeyID string `json:"AccessKeyId"`
|
||||||
|
|
||||||
|
// The secret access key that can be used to sign requests.
|
||||||
SecretAccessKey string
|
SecretAccessKey string
|
||||||
SessionToken string
|
|
||||||
Expiration *time.Time
|
// The token that users must pass to the service API to use the temporary credentials.
|
||||||
|
SessionToken string
|
||||||
|
|
||||||
|
// The date on which the current credentials expire.
|
||||||
|
Expiration *time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve executes the credential process command and returns the
|
// Retrieve executes the credential process command and returns the
|
||||||
|
|
@ -166,7 +178,7 @@ func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize and validate response
|
// Serialize and validate response
|
||||||
resp := &credentialProcessResponse{}
|
resp := &CredentialProcessResponse{}
|
||||||
if err = json.Unmarshal(out, resp); err != nil {
|
if err = json.Unmarshal(out, resp); err != nil {
|
||||||
return aws.Credentials{Source: ProviderName}, &ProviderError{
|
return aws.Credentials{Source: ProviderName}, &ProviderError{
|
||||||
Err: fmt.Errorf("parse failed of process output: %s, error: %w", out, err),
|
Err: fmt.Errorf("parse failed of process output: %s, error: %w", out, err),
|
||||||
|
|
|
||||||
|
|
@ -1,63 +1,81 @@
|
||||||
// Package ssocreds provides a credential provider for retrieving temporary AWS credentials using an SSO access token.
|
// Package ssocreds provides a credential provider for retrieving temporary AWS
|
||||||
|
// credentials using an SSO access token.
|
||||||
//
|
//
|
||||||
// IMPORTANT: The provider in this package does not initiate or perform the AWS SSO login flow. The SDK provider
|
// IMPORTANT: The provider in this package does not initiate or perform the AWS
|
||||||
// expects that you have already performed the SSO login flow using AWS CLI using the "aws sso login" command, or by
|
// SSO login flow. The SDK provider expects that you have already performed the
|
||||||
// some other mechanism. The provider must find a valid non-expired access token for the AWS SSO user portal URL in
|
// SSO login flow using AWS CLI using the "aws sso login" command, or by some
|
||||||
// ~/.aws/sso/cache. If a cached token is not found, it is expired, or the file is malformed an error will be returned.
|
// other mechanism. The provider must find a valid non-expired access token for
|
||||||
|
// the AWS SSO user portal URL in ~/.aws/sso/cache. If a cached token is not
|
||||||
|
// found, it is expired, or the file is malformed an error will be returned.
|
||||||
//
|
//
|
||||||
// Loading AWS SSO credentials with the AWS shared configuration file
|
// # Loading AWS SSO credentials with the AWS shared configuration file
|
||||||
//
|
//
|
||||||
// You can use configure AWS SSO credentials from the AWS shared configuration file by
|
// You can use configure AWS SSO credentials from the AWS shared configuration file by
|
||||||
// providing the specifying the required keys in the profile:
|
// specifying the required keys in the profile and referencing an sso-session:
|
||||||
//
|
//
|
||||||
// sso_account_id
|
// sso_session
|
||||||
// sso_region
|
// sso_account_id
|
||||||
// sso_role_name
|
// sso_role_name
|
||||||
// sso_start_url
|
|
||||||
//
|
//
|
||||||
// For example, the following defines a profile "devsso" and specifies the AWS SSO parameters that defines the target
|
// For example, the following defines a profile "devsso" and specifies the AWS
|
||||||
// account, role, sign-on portal, and the region where the user portal is located. Note: all SSO arguments must be
|
// SSO parameters that defines the target account, role, sign-on portal, and
|
||||||
|
// the region where the user portal is located. Note: all SSO arguments must be
|
||||||
// provided, or an error will be returned.
|
// provided, or an error will be returned.
|
||||||
//
|
//
|
||||||
// [profile devsso]
|
// [profile devsso]
|
||||||
// sso_start_url = https://my-sso-portal.awsapps.com/start
|
// sso_session = dev-session
|
||||||
// sso_role_name = SSOReadOnlyRole
|
// sso_role_name = SSOReadOnlyRole
|
||||||
// sso_region = us-east-1
|
// sso_account_id = 123456789012
|
||||||
// sso_account_id = 123456789012
|
|
||||||
//
|
//
|
||||||
// Using the config module, you can load the AWS SDK shared configuration, and specify that this profile be used to
|
// [sso-session dev-session]
|
||||||
// retrieve credentials. For example:
|
// sso_start_url = https://my-sso-portal.awsapps.com/start
|
||||||
|
// sso_region = us-east-1
|
||||||
|
// sso_registration_scopes = sso:account:access
|
||||||
//
|
//
|
||||||
// config, err := config.LoadDefaultConfig(context.TODO(), config.WithSharedConfigProfile("devsso"))
|
// Using the config module, you can load the AWS SDK shared configuration, and
|
||||||
// if err != nil {
|
// specify that this profile be used to retrieve credentials. For example:
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// Programmatically loading AWS SSO credentials directly
|
// config, err := config.LoadDefaultConfig(context.TODO(), config.WithSharedConfigProfile("devsso"))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// You can programmatically construct the AWS SSO Provider in your application, and provide the necessary information
|
// # Programmatically loading AWS SSO credentials directly
|
||||||
// to load and retrieve temporary credentials using an access token from ~/.aws/sso/cache.
|
|
||||||
//
|
//
|
||||||
// client := sso.NewFromConfig(cfg)
|
// You can programmatically construct the AWS SSO Provider in your application,
|
||||||
|
// and provide the necessary information to load and retrieve temporary
|
||||||
|
// credentials using an access token from ~/.aws/sso/cache.
|
||||||
//
|
//
|
||||||
// var provider aws.CredentialsProvider
|
// ssoClient := sso.NewFromConfig(cfg)
|
||||||
// provider = ssocreds.New(client, "123456789012", "SSOReadOnlyRole", "us-east-1", "https://my-sso-portal.awsapps.com/start")
|
// ssoOidcClient := ssooidc.NewFromConfig(cfg)
|
||||||
|
// tokenPath, err := ssocreds.StandardCachedTokenFilepath("dev-session")
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// // Wrap the provider with aws.CredentialsCache to cache the credentials until their expire time
|
// var provider aws.CredentialsProvider
|
||||||
// provider = aws.NewCredentialsCache(provider)
|
// provider = ssocreds.New(ssoClient, "123456789012", "SSOReadOnlyRole", "https://my-sso-portal.awsapps.com/start", func(options *ssocreds.Options) {
|
||||||
|
// options.SSOTokenProvider = ssocreds.NewSSOTokenProvider(ssoOidcClient, tokenPath)
|
||||||
|
// })
|
||||||
//
|
//
|
||||||
// credentials, err := provider.Retrieve(context.TODO())
|
// // Wrap the provider with aws.CredentialsCache to cache the credentials until their expire time
|
||||||
// if err != nil {
|
// provider = aws.NewCredentialsCache(provider)
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// It is important that you wrap the Provider with aws.CredentialsCache if you are programmatically constructing the
|
// credentials, err := provider.Retrieve(context.TODO())
|
||||||
// provider directly. This prevents your application from accessing the cached access token and requesting new
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// It is important that you wrap the Provider with aws.CredentialsCache if you
|
||||||
|
// are programmatically constructing the provider directly. This prevents your
|
||||||
|
// application from accessing the cached access token and requesting new
|
||||||
// credentials each time the credentials are used.
|
// credentials each time the credentials are used.
|
||||||
//
|
//
|
||||||
// Additional Resources
|
// # Additional Resources
|
||||||
//
|
//
|
||||||
// Configuring the AWS CLI to use AWS Single Sign-On: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html
|
// Configuring the AWS CLI to use AWS Single Sign-On:
|
||||||
|
// https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html
|
||||||
//
|
//
|
||||||
// AWS Single Sign-On User Guide: https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html
|
// AWS Single Sign-On User Guide:
|
||||||
|
// https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html
|
||||||
package ssocreds
|
package ssocreds
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
//go:build !windows
|
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package ssocreds
|
|
||||||
|
|
||||||
import "os"
|
|
||||||
|
|
||||||
func getHomeDirectory() string {
|
|
||||||
return os.Getenv("HOME")
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package ssocreds
|
|
||||||
|
|
||||||
import "os"
|
|
||||||
|
|
||||||
func getHomeDirectory() string {
|
|
||||||
return os.Getenv("USERPROFILE")
|
|
||||||
}
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
package ssocreds
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/sha1"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/aws"
|
|
||||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
|
||||||
"github.com/aws/aws-sdk-go-v2/service/sso"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProviderName is the name of the provider used to specify the source of credentials.
|
|
||||||
const ProviderName = "SSOProvider"
|
|
||||||
|
|
||||||
var defaultCacheLocation func() string
|
|
||||||
|
|
||||||
func defaultCacheLocationImpl() string {
|
|
||||||
return filepath.Join(getHomeDirectory(), ".aws", "sso", "cache")
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
defaultCacheLocation = defaultCacheLocationImpl
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRoleCredentialsAPIClient is a API client that implements the GetRoleCredentials operation.
|
|
||||||
type GetRoleCredentialsAPIClient interface {
|
|
||||||
GetRoleCredentials(ctx context.Context, params *sso.GetRoleCredentialsInput, optFns ...func(*sso.Options)) (*sso.GetRoleCredentialsOutput, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options is the Provider options structure.
|
|
||||||
type Options struct {
|
|
||||||
// The Client which is configured for the AWS Region where the AWS SSO user portal is located.
|
|
||||||
Client GetRoleCredentialsAPIClient
|
|
||||||
|
|
||||||
// The AWS account that is assigned to the user.
|
|
||||||
AccountID string
|
|
||||||
|
|
||||||
// The role name that is assigned to the user.
|
|
||||||
RoleName string
|
|
||||||
|
|
||||||
// The URL that points to the organization's AWS Single Sign-On (AWS SSO) user portal.
|
|
||||||
StartURL string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provider is an AWS credential provider that retrieves temporary AWS credentials by exchanging an SSO login token.
|
|
||||||
type Provider struct {
|
|
||||||
options Options
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new AWS Single Sign-On (AWS SSO) credential provider. The provided client is expected to be configured
|
|
||||||
// for the AWS Region where the AWS SSO user portal is located.
|
|
||||||
func New(client GetRoleCredentialsAPIClient, accountID, roleName, startURL string, optFns ...func(options *Options)) *Provider {
|
|
||||||
options := Options{
|
|
||||||
Client: client,
|
|
||||||
AccountID: accountID,
|
|
||||||
RoleName: roleName,
|
|
||||||
StartURL: startURL,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fn := range optFns {
|
|
||||||
fn(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Provider{
|
|
||||||
options: options,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve retrieves temporary AWS credentials from the configured Amazon Single Sign-On (AWS SSO) user portal
|
|
||||||
// by exchanging the accessToken present in ~/.aws/sso/cache.
|
|
||||||
func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) {
|
|
||||||
tokenFile, err := loadTokenFile(p.options.StartURL)
|
|
||||||
if err != nil {
|
|
||||||
return aws.Credentials{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
output, err := p.options.Client.GetRoleCredentials(ctx, &sso.GetRoleCredentialsInput{
|
|
||||||
AccessToken: &tokenFile.AccessToken,
|
|
||||||
AccountId: &p.options.AccountID,
|
|
||||||
RoleName: &p.options.RoleName,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return aws.Credentials{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return aws.Credentials{
|
|
||||||
AccessKeyID: aws.ToString(output.RoleCredentials.AccessKeyId),
|
|
||||||
SecretAccessKey: aws.ToString(output.RoleCredentials.SecretAccessKey),
|
|
||||||
SessionToken: aws.ToString(output.RoleCredentials.SessionToken),
|
|
||||||
Expires: time.Unix(0, output.RoleCredentials.Expiration*int64(time.Millisecond)).UTC(),
|
|
||||||
CanExpire: true,
|
|
||||||
Source: ProviderName,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCacheFileName(url string) (string, error) {
|
|
||||||
hash := sha1.New()
|
|
||||||
_, err := hash.Write([]byte(url))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return strings.ToLower(hex.EncodeToString(hash.Sum(nil))) + ".json", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type rfc3339 time.Time
|
|
||||||
|
|
||||||
func (r *rfc3339) UnmarshalJSON(bytes []byte) error {
|
|
||||||
var value string
|
|
||||||
|
|
||||||
if err := json.Unmarshal(bytes, &value); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
parse, err := time.Parse(time.RFC3339, value)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("expected RFC3339 timestamp: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
*r = rfc3339(parse)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type token struct {
|
|
||||||
AccessToken string `json:"accessToken"`
|
|
||||||
ExpiresAt rfc3339 `json:"expiresAt"`
|
|
||||||
Region string `json:"region,omitempty"`
|
|
||||||
StartURL string `json:"startUrl,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t token) Expired() bool {
|
|
||||||
return sdk.NowTime().Round(0).After(time.Time(t.ExpiresAt))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidTokenError is the error type that is returned if loaded token has expired or is otherwise invalid.
|
|
||||||
// To refresh the SSO session run aws sso login with the corresponding profile.
|
|
||||||
type InvalidTokenError struct {
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *InvalidTokenError) Unwrap() error {
|
|
||||||
return i.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *InvalidTokenError) Error() string {
|
|
||||||
const msg = "the SSO session has expired or is invalid"
|
|
||||||
if i.Err == nil {
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
return msg + ": " + i.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadTokenFile(startURL string) (t token, err error) {
|
|
||||||
key, err := getCacheFileName(startURL)
|
|
||||||
if err != nil {
|
|
||||||
return token{}, &InvalidTokenError{Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileBytes, err := ioutil.ReadFile(filepath.Join(defaultCacheLocation(), key))
|
|
||||||
if err != nil {
|
|
||||||
return token{}, &InvalidTokenError{Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(fileBytes, &t); err != nil {
|
|
||||||
return token{}, &InvalidTokenError{Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(t.AccessToken) == 0 {
|
|
||||||
return token{}, &InvalidTokenError{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.Expired() {
|
|
||||||
return token{}, &InvalidTokenError{Err: fmt.Errorf("access token is expired")}
|
|
||||||
}
|
|
||||||
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
233
vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go
generated
vendored
Normal file
233
vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go
generated
vendored
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
package ssocreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/internal/shareddefaults"
|
||||||
|
)
|
||||||
|
|
||||||
|
var osUserHomeDur = shareddefaults.UserHomeDir
|
||||||
|
|
||||||
|
// StandardCachedTokenFilepath returns the filepath for the cached SSO token file, or
|
||||||
|
// error if unable get derive the path. Key that will be used to compute a SHA1
|
||||||
|
// value that is hex encoded.
|
||||||
|
//
|
||||||
|
// Derives the filepath using the Key as:
|
||||||
|
//
|
||||||
|
// ~/.aws/sso/cache/<sha1-hex-encoded-key>.json
|
||||||
|
func StandardCachedTokenFilepath(key string) (string, error) {
|
||||||
|
homeDir := osUserHomeDur()
|
||||||
|
if len(homeDir) == 0 {
|
||||||
|
return "", fmt.Errorf("unable to get USER's home directory for cached token")
|
||||||
|
}
|
||||||
|
hash := sha1.New()
|
||||||
|
if _, err := hash.Write([]byte(key)); err != nil {
|
||||||
|
return "", fmt.Errorf("unable to compute cached token filepath key SHA1 hash, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheFilename := strings.ToLower(hex.EncodeToString(hash.Sum(nil))) + ".json"
|
||||||
|
|
||||||
|
return filepath.Join(homeDir, ".aws", "sso", "cache", cacheFilename), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenKnownFields struct {
|
||||||
|
AccessToken string `json:"accessToken,omitempty"`
|
||||||
|
ExpiresAt *rfc3339 `json:"expiresAt,omitempty"`
|
||||||
|
|
||||||
|
RefreshToken string `json:"refreshToken,omitempty"`
|
||||||
|
ClientID string `json:"clientId,omitempty"`
|
||||||
|
ClientSecret string `json:"clientSecret,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type token struct {
|
||||||
|
tokenKnownFields
|
||||||
|
UnknownFields map[string]interface{} `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t token) MarshalJSON() ([]byte, error) {
|
||||||
|
fields := map[string]interface{}{}
|
||||||
|
|
||||||
|
setTokenFieldString(fields, "accessToken", t.AccessToken)
|
||||||
|
setTokenFieldRFC3339(fields, "expiresAt", t.ExpiresAt)
|
||||||
|
|
||||||
|
setTokenFieldString(fields, "refreshToken", t.RefreshToken)
|
||||||
|
setTokenFieldString(fields, "clientId", t.ClientID)
|
||||||
|
setTokenFieldString(fields, "clientSecret", t.ClientSecret)
|
||||||
|
|
||||||
|
for k, v := range t.UnknownFields {
|
||||||
|
if _, ok := fields[k]; ok {
|
||||||
|
return nil, fmt.Errorf("unknown token field %v, duplicates known field", k)
|
||||||
|
}
|
||||||
|
fields[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTokenFieldString(fields map[string]interface{}, key, value string) {
|
||||||
|
if value == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fields[key] = value
|
||||||
|
}
|
||||||
|
func setTokenFieldRFC3339(fields map[string]interface{}, key string, value *rfc3339) {
|
||||||
|
if value == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fields[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *token) UnmarshalJSON(b []byte) error {
|
||||||
|
var fields map[string]interface{}
|
||||||
|
if err := json.Unmarshal(b, &fields); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t.UnknownFields = map[string]interface{}{}
|
||||||
|
|
||||||
|
for k, v := range fields {
|
||||||
|
var err error
|
||||||
|
switch k {
|
||||||
|
case "accessToken":
|
||||||
|
err = getTokenFieldString(v, &t.AccessToken)
|
||||||
|
case "expiresAt":
|
||||||
|
err = getTokenFieldRFC3339(v, &t.ExpiresAt)
|
||||||
|
case "refreshToken":
|
||||||
|
err = getTokenFieldString(v, &t.RefreshToken)
|
||||||
|
case "clientId":
|
||||||
|
err = getTokenFieldString(v, &t.ClientID)
|
||||||
|
case "clientSecret":
|
||||||
|
err = getTokenFieldString(v, &t.ClientSecret)
|
||||||
|
default:
|
||||||
|
t.UnknownFields[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field %q, %w", k, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTokenFieldString(v interface{}, value *string) error {
|
||||||
|
var ok bool
|
||||||
|
*value, ok = v.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("expect value to be string, got %T", v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTokenFieldRFC3339(v interface{}, value **rfc3339) error {
|
||||||
|
var stringValue string
|
||||||
|
if err := getTokenFieldString(v, &stringValue); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
timeValue, err := parseRFC3339(stringValue)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*value = &timeValue
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCachedToken(filename string) (token, error) {
|
||||||
|
fileBytes, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return token{}, fmt.Errorf("failed to read cached SSO token file, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var t token
|
||||||
|
if err := json.Unmarshal(fileBytes, &t); err != nil {
|
||||||
|
return token{}, fmt.Errorf("failed to parse cached SSO token file, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(t.AccessToken) == 0 || t.ExpiresAt == nil || time.Time(*t.ExpiresAt).IsZero() {
|
||||||
|
return token{}, fmt.Errorf(
|
||||||
|
"cached SSO token must contain accessToken and expiresAt fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func storeCachedToken(filename string, t token, fileMode os.FileMode) (err error) {
|
||||||
|
tmpFilename := filename + ".tmp-" + strconv.FormatInt(sdk.NowTime().UnixNano(), 10)
|
||||||
|
if err := writeCacheFile(tmpFilename, fileMode, t); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Rename(tmpFilename, filename); err != nil {
|
||||||
|
return fmt.Errorf("failed to replace old cached SSO token file, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeCacheFile(filename string, fileMode os.FileMode, t token) (err error) {
|
||||||
|
var f *os.File
|
||||||
|
f, err = os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_RDWR, fileMode)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create cached SSO token file %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
closeErr := f.Close()
|
||||||
|
if err == nil && closeErr != nil {
|
||||||
|
err = fmt.Errorf("failed to close cached SSO token file, %w", closeErr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
encoder := json.NewEncoder(f)
|
||||||
|
|
||||||
|
if err = encoder.Encode(t); err != nil {
|
||||||
|
return fmt.Errorf("failed to serialize cached SSO token, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type rfc3339 time.Time
|
||||||
|
|
||||||
|
func parseRFC3339(v string) (rfc3339, error) {
|
||||||
|
parsed, err := time.Parse(time.RFC3339, v)
|
||||||
|
if err != nil {
|
||||||
|
return rfc3339{}, fmt.Errorf("expected RFC3339 timestamp: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rfc3339(parsed), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rfc3339) UnmarshalJSON(bytes []byte) (err error) {
|
||||||
|
var value string
|
||||||
|
|
||||||
|
// Use JSON unmarshal to unescape the quoted value making use of JSON's
|
||||||
|
// unquoting rules.
|
||||||
|
if err = json.Unmarshal(bytes, &value); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*r, err = parseRFC3339(value)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rfc3339) MarshalJSON() ([]byte, error) {
|
||||||
|
value := time.Time(*r).Format(time.RFC3339)
|
||||||
|
|
||||||
|
// Use JSON unmarshal to unescape the quoted value making use of JSON's
|
||||||
|
// quoting rules.
|
||||||
|
return json.Marshal(value)
|
||||||
|
}
|
||||||
152
vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go
generated
vendored
Normal file
152
vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go
generated
vendored
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
package ssocreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/sso"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProviderName is the name of the provider used to specify the source of
|
||||||
|
// credentials.
|
||||||
|
const ProviderName = "SSOProvider"
|
||||||
|
|
||||||
|
// GetRoleCredentialsAPIClient is a API client that implements the
|
||||||
|
// GetRoleCredentials operation.
|
||||||
|
type GetRoleCredentialsAPIClient interface {
|
||||||
|
GetRoleCredentials(context.Context, *sso.GetRoleCredentialsInput, ...func(*sso.Options)) (
|
||||||
|
*sso.GetRoleCredentialsOutput, error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options is the Provider options structure.
|
||||||
|
type Options struct {
|
||||||
|
// The Client which is configured for the AWS Region where the AWS SSO user
|
||||||
|
// portal is located.
|
||||||
|
Client GetRoleCredentialsAPIClient
|
||||||
|
|
||||||
|
// The AWS account that is assigned to the user.
|
||||||
|
AccountID string
|
||||||
|
|
||||||
|
// The role name that is assigned to the user.
|
||||||
|
RoleName string
|
||||||
|
|
||||||
|
// The URL that points to the organization's AWS Single Sign-On (AWS SSO)
|
||||||
|
// user portal.
|
||||||
|
StartURL string
|
||||||
|
|
||||||
|
// The filepath the cached token will be retrieved from. If unset Provider will
|
||||||
|
// use the startURL to determine the filepath at.
|
||||||
|
//
|
||||||
|
// ~/.aws/sso/cache/<sha1-hex-encoded-startURL>.json
|
||||||
|
//
|
||||||
|
// If custom cached token filepath is used, the Provider's startUrl
|
||||||
|
// parameter will be ignored.
|
||||||
|
CachedTokenFilepath string
|
||||||
|
|
||||||
|
// Used by the SSOCredentialProvider if a token configuration
|
||||||
|
// profile is used in the shared config
|
||||||
|
SSOTokenProvider *SSOTokenProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider is an AWS credential provider that retrieves temporary AWS
|
||||||
|
// credentials by exchanging an SSO login token.
|
||||||
|
type Provider struct {
|
||||||
|
options Options
|
||||||
|
|
||||||
|
cachedTokenFilepath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new AWS Single Sign-On (AWS SSO) credential provider. The
|
||||||
|
// provided client is expected to be configured for the AWS Region where the
|
||||||
|
// AWS SSO user portal is located.
|
||||||
|
func New(client GetRoleCredentialsAPIClient, accountID, roleName, startURL string, optFns ...func(options *Options)) *Provider {
|
||||||
|
options := Options{
|
||||||
|
Client: client,
|
||||||
|
AccountID: accountID,
|
||||||
|
RoleName: roleName,
|
||||||
|
StartURL: startURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fn := range optFns {
|
||||||
|
fn(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Provider{
|
||||||
|
options: options,
|
||||||
|
cachedTokenFilepath: options.CachedTokenFilepath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve retrieves temporary AWS credentials from the configured Amazon
|
||||||
|
// Single Sign-On (AWS SSO) user portal by exchanging the accessToken present
|
||||||
|
// in ~/.aws/sso/cache. However, if a token provider configuration exists
|
||||||
|
// in the shared config, then we ought to use the token provider rather then
|
||||||
|
// direct access on the cached token.
|
||||||
|
func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) {
|
||||||
|
var accessToken *string
|
||||||
|
if p.options.SSOTokenProvider != nil {
|
||||||
|
token, err := p.options.SSOTokenProvider.RetrieveBearerToken(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return aws.Credentials{}, err
|
||||||
|
}
|
||||||
|
accessToken = &token.Value
|
||||||
|
} else {
|
||||||
|
if p.cachedTokenFilepath == "" {
|
||||||
|
cachedTokenFilepath, err := StandardCachedTokenFilepath(p.options.StartURL)
|
||||||
|
if err != nil {
|
||||||
|
return aws.Credentials{}, &InvalidTokenError{Err: err}
|
||||||
|
}
|
||||||
|
p.cachedTokenFilepath = cachedTokenFilepath
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenFile, err := loadCachedToken(p.cachedTokenFilepath)
|
||||||
|
if err != nil {
|
||||||
|
return aws.Credentials{}, &InvalidTokenError{Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tokenFile.ExpiresAt == nil || sdk.NowTime().After(time.Time(*tokenFile.ExpiresAt)) {
|
||||||
|
return aws.Credentials{}, &InvalidTokenError{}
|
||||||
|
}
|
||||||
|
accessToken = &tokenFile.AccessToken
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := p.options.Client.GetRoleCredentials(ctx, &sso.GetRoleCredentialsInput{
|
||||||
|
AccessToken: accessToken,
|
||||||
|
AccountId: &p.options.AccountID,
|
||||||
|
RoleName: &p.options.RoleName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return aws.Credentials{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return aws.Credentials{
|
||||||
|
AccessKeyID: aws.ToString(output.RoleCredentials.AccessKeyId),
|
||||||
|
SecretAccessKey: aws.ToString(output.RoleCredentials.SecretAccessKey),
|
||||||
|
SessionToken: aws.ToString(output.RoleCredentials.SessionToken),
|
||||||
|
CanExpire: true,
|
||||||
|
Expires: time.Unix(0, output.RoleCredentials.Expiration*int64(time.Millisecond)).UTC(),
|
||||||
|
Source: ProviderName,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidTokenError is the error type that is returned if loaded token has
|
||||||
|
// expired or is otherwise invalid. To refresh the SSO session run AWS SSO
|
||||||
|
// login with the corresponding profile.
|
||||||
|
type InvalidTokenError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *InvalidTokenError) Unwrap() error {
|
||||||
|
return i.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *InvalidTokenError) Error() string {
|
||||||
|
const msg = "the SSO session has expired or is invalid"
|
||||||
|
if i.Err == nil {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
return msg + ": " + i.Err.Error()
|
||||||
|
}
|
||||||
147
vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_token_provider.go
generated
vendored
Normal file
147
vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_token_provider.go
generated
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
package ssocreds
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/ssooidc"
|
||||||
|
"github.com/aws/smithy-go/auth/bearer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateTokenAPIClient provides the interface for the SSOTokenProvider's API
|
||||||
|
// client for calling CreateToken operation to refresh the SSO token.
|
||||||
|
type CreateTokenAPIClient interface {
|
||||||
|
CreateToken(context.Context, *ssooidc.CreateTokenInput, ...func(*ssooidc.Options)) (
|
||||||
|
*ssooidc.CreateTokenOutput, error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSOTokenProviderOptions provides the options for configuring the
|
||||||
|
// SSOTokenProvider.
|
||||||
|
type SSOTokenProviderOptions struct {
|
||||||
|
// Client that can be overridden
|
||||||
|
Client CreateTokenAPIClient
|
||||||
|
|
||||||
|
// The set of API Client options to be applied when invoking the
|
||||||
|
// CreateToken operation.
|
||||||
|
ClientOptions []func(*ssooidc.Options)
|
||||||
|
|
||||||
|
// The path the file containing the cached SSO token will be read from.
|
||||||
|
// Initialized the NewSSOTokenProvider's cachedTokenFilepath parameter.
|
||||||
|
CachedTokenFilepath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSOTokenProvider provides an utility for refreshing SSO AccessTokens for
|
||||||
|
// Bearer Authentication. The SSOTokenProvider can only be used to refresh
|
||||||
|
// already cached SSO Tokens. This utility cannot perform the initial SSO
|
||||||
|
// create token.
|
||||||
|
//
|
||||||
|
// The SSOTokenProvider is not safe to use concurrently. It must be wrapped in
|
||||||
|
// a utility such as smithy-go's auth/bearer#TokenCache. The SDK's
|
||||||
|
// config.LoadDefaultConfig will automatically wrap the SSOTokenProvider with
|
||||||
|
// the smithy-go TokenCache, if the external configuration loaded configured
|
||||||
|
// for an SSO session.
|
||||||
|
//
|
||||||
|
// The initial SSO create token should be preformed with the AWS CLI before the
|
||||||
|
// Go application using the SSOTokenProvider will need to retrieve the SSO
|
||||||
|
// token. If the AWS CLI has not created the token cache file, this provider
|
||||||
|
// will return an error when attempting to retrieve the cached token.
|
||||||
|
//
|
||||||
|
// This provider will attempt to refresh the cached SSO token periodically if
|
||||||
|
// needed when RetrieveBearerToken is called.
|
||||||
|
//
|
||||||
|
// A utility such as the AWS CLI must be used to initially create the SSO
|
||||||
|
// session and cached token file.
|
||||||
|
// https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html
|
||||||
|
type SSOTokenProvider struct {
|
||||||
|
options SSOTokenProviderOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ bearer.TokenProvider = (*SSOTokenProvider)(nil)
|
||||||
|
|
||||||
|
// NewSSOTokenProvider returns an initialized SSOTokenProvider that will
|
||||||
|
// periodically refresh the SSO token cached stored in the cachedTokenFilepath.
|
||||||
|
// The cachedTokenFilepath file's content will be rewritten by the token
|
||||||
|
// provider when the token is refreshed.
|
||||||
|
//
|
||||||
|
// The client must be configured for the AWS region the SSO token was created for.
|
||||||
|
func NewSSOTokenProvider(client CreateTokenAPIClient, cachedTokenFilepath string, optFns ...func(o *SSOTokenProviderOptions)) *SSOTokenProvider {
|
||||||
|
options := SSOTokenProviderOptions{
|
||||||
|
Client: client,
|
||||||
|
CachedTokenFilepath: cachedTokenFilepath,
|
||||||
|
}
|
||||||
|
for _, fn := range optFns {
|
||||||
|
fn(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := &SSOTokenProvider{
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveBearerToken returns the SSO token stored in the cachedTokenFilepath
|
||||||
|
// the SSOTokenProvider was created with. If the token has expired
|
||||||
|
// RetrieveBearerToken will attempt to refresh it. If the token cannot be
|
||||||
|
// refreshed or is not present an error will be returned.
|
||||||
|
//
|
||||||
|
// A utility such as the AWS CLI must be used to initially create the SSO
|
||||||
|
// session and cached token file. https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html
|
||||||
|
func (p SSOTokenProvider) RetrieveBearerToken(ctx context.Context) (bearer.Token, error) {
|
||||||
|
cachedToken, err := loadCachedToken(p.options.CachedTokenFilepath)
|
||||||
|
if err != nil {
|
||||||
|
return bearer.Token{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if cachedToken.ExpiresAt != nil && sdk.NowTime().After(time.Time(*cachedToken.ExpiresAt)) {
|
||||||
|
cachedToken, err = p.refreshToken(ctx, cachedToken)
|
||||||
|
if err != nil {
|
||||||
|
return bearer.Token{}, fmt.Errorf("refresh cached SSO token failed, %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expiresAt := aws.ToTime((*time.Time)(cachedToken.ExpiresAt))
|
||||||
|
return bearer.Token{
|
||||||
|
Value: cachedToken.AccessToken,
|
||||||
|
CanExpire: !expiresAt.IsZero(),
|
||||||
|
Expires: expiresAt,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p SSOTokenProvider) refreshToken(ctx context.Context, cachedToken token) (token, error) {
|
||||||
|
if cachedToken.ClientSecret == "" || cachedToken.ClientID == "" || cachedToken.RefreshToken == "" {
|
||||||
|
return token{}, fmt.Errorf("cached SSO token is expired, or not present, and cannot be refreshed")
|
||||||
|
}
|
||||||
|
|
||||||
|
createResult, err := p.options.Client.CreateToken(ctx, &ssooidc.CreateTokenInput{
|
||||||
|
ClientId: &cachedToken.ClientID,
|
||||||
|
ClientSecret: &cachedToken.ClientSecret,
|
||||||
|
RefreshToken: &cachedToken.RefreshToken,
|
||||||
|
GrantType: aws.String("refresh_token"),
|
||||||
|
}, p.options.ClientOptions...)
|
||||||
|
if err != nil {
|
||||||
|
return token{}, fmt.Errorf("unable to refresh SSO token, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expiresAt := sdk.NowTime().Add(time.Duration(createResult.ExpiresIn) * time.Second)
|
||||||
|
|
||||||
|
cachedToken.AccessToken = aws.ToString(createResult.AccessToken)
|
||||||
|
cachedToken.ExpiresAt = (*rfc3339)(&expiresAt)
|
||||||
|
cachedToken.RefreshToken = aws.ToString(createResult.RefreshToken)
|
||||||
|
|
||||||
|
fileInfo, err := os.Stat(p.options.CachedTokenFilepath)
|
||||||
|
if err != nil {
|
||||||
|
return token{}, fmt.Errorf("failed to stat cached SSO token file %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = storeCachedToken(p.options.CachedTokenFilepath, cachedToken, fileInfo.Mode()); err != nil {
|
||||||
|
return token{}, fmt.Errorf("unable to cache refreshed SSO token, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedToken, nil
|
||||||
|
}
|
||||||
98
vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/assume_role_provider.go
generated
vendored
98
vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/assume_role_provider.go
generated
vendored
|
|
@ -8,31 +8,31 @@
|
||||||
// ensure synchronous usage of the AssumeRoleProvider if the value is shared
|
// ensure synchronous usage of the AssumeRoleProvider if the value is shared
|
||||||
// between multiple Credentials or service clients.
|
// between multiple Credentials or service clients.
|
||||||
//
|
//
|
||||||
// Assume Role
|
// # Assume Role
|
||||||
//
|
//
|
||||||
// To assume an IAM role using STS with the SDK you can create a new Credentials
|
// To assume an IAM role using STS with the SDK you can create a new Credentials
|
||||||
// with the SDKs's stscreds package.
|
// with the SDKs's stscreds package.
|
||||||
//
|
//
|
||||||
// // Initial credentials loaded from SDK's default credential chain. Such as
|
// // Initial credentials loaded from SDK's default credential chain. Such as
|
||||||
// // the environment, shared credentials (~/.aws/credentials), or EC2 Instance
|
// // the environment, shared credentials (~/.aws/credentials), or EC2 Instance
|
||||||
// // Role. These credentials will be used to to make the STS Assume Role API.
|
// // Role. These credentials will be used to to make the STS Assume Role API.
|
||||||
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// panic(err)
|
// panic(err)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // Create the credentials from AssumeRoleProvider to assume the role
|
// // Create the credentials from AssumeRoleProvider to assume the role
|
||||||
// // referenced by the "myRoleARN" ARN.
|
// // referenced by the "myRoleARN" ARN.
|
||||||
// stsSvc := sts.NewFromConfig(cfg)
|
// stsSvc := sts.NewFromConfig(cfg)
|
||||||
// creds := stscreds.NewAssumeRoleProvider(stsSvc, "myRoleArn")
|
// creds := stscreds.NewAssumeRoleProvider(stsSvc, "myRoleArn")
|
||||||
//
|
//
|
||||||
// cfg.Credentials = aws.NewCredentialsCache(creds)
|
// cfg.Credentials = aws.NewCredentialsCache(creds)
|
||||||
//
|
//
|
||||||
// // Create service client value configured for credentials
|
// // Create service client value configured for credentials
|
||||||
// // from assumed role.
|
// // from assumed role.
|
||||||
// svc := s3.NewFromConfig(cfg)
|
// svc := s3.NewFromConfig(cfg)
|
||||||
//
|
//
|
||||||
// Assume Role with custom MFA Token provider
|
// # Assume Role with custom MFA Token provider
|
||||||
//
|
//
|
||||||
// To assume an IAM role with a MFA token you can either specify a custom MFA
|
// To assume an IAM role with a MFA token you can either specify a custom MFA
|
||||||
// token provider or use the SDK's built in StdinTokenProvider that will prompt
|
// token provider or use the SDK's built in StdinTokenProvider that will prompt
|
||||||
|
|
@ -43,29 +43,29 @@
|
||||||
// With a custom token provider, the provider is responsible for refreshing the
|
// With a custom token provider, the provider is responsible for refreshing the
|
||||||
// token code when called.
|
// token code when called.
|
||||||
//
|
//
|
||||||
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// panic(err)
|
// panic(err)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// staticTokenProvider := func() (string, error) {
|
// staticTokenProvider := func() (string, error) {
|
||||||
// return someTokenCode, nil
|
// return someTokenCode, nil
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // Create the credentials from AssumeRoleProvider to assume the role
|
// // Create the credentials from AssumeRoleProvider to assume the role
|
||||||
// // referenced by the "myRoleARN" ARN using the MFA token code provided.
|
// // referenced by the "myRoleARN" ARN using the MFA token code provided.
|
||||||
// creds := stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), "myRoleArn", func(o *stscreds.AssumeRoleOptions) {
|
// creds := stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), "myRoleArn", func(o *stscreds.AssumeRoleOptions) {
|
||||||
// o.SerialNumber = aws.String("myTokenSerialNumber")
|
// o.SerialNumber = aws.String("myTokenSerialNumber")
|
||||||
// o.TokenProvider = staticTokenProvider
|
// o.TokenProvider = staticTokenProvider
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// cfg.Credentials = aws.NewCredentialsCache(creds)
|
// cfg.Credentials = aws.NewCredentialsCache(creds)
|
||||||
//
|
//
|
||||||
// // Create service client value configured for credentials
|
// // Create service client value configured for credentials
|
||||||
// // from assumed role.
|
// // from assumed role.
|
||||||
// svc := s3.NewFromConfig(cfg)
|
// svc := s3.NewFromConfig(cfg)
|
||||||
//
|
//
|
||||||
// Assume Role with MFA Token Provider
|
// # Assume Role with MFA Token Provider
|
||||||
//
|
//
|
||||||
// To assume an IAM role with MFA for longer running tasks where the credentials
|
// To assume an IAM role with MFA for longer running tasks where the credentials
|
||||||
// may need to be refreshed setting the TokenProvider field of AssumeRoleProvider
|
// may need to be refreshed setting the TokenProvider field of AssumeRoleProvider
|
||||||
|
|
@ -80,23 +80,23 @@
|
||||||
// have undesirable results as the StdinTokenProvider will not be synchronized. A
|
// have undesirable results as the StdinTokenProvider will not be synchronized. A
|
||||||
// single Credentials with an AssumeRoleProvider can be shared safely.
|
// single Credentials with an AssumeRoleProvider can be shared safely.
|
||||||
//
|
//
|
||||||
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// panic(err)
|
// panic(err)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // Create the credentials from AssumeRoleProvider to assume the role
|
// // Create the credentials from AssumeRoleProvider to assume the role
|
||||||
// // referenced by the "myRoleARN" ARN using the MFA token code provided.
|
// // referenced by the "myRoleARN" ARN using the MFA token code provided.
|
||||||
// creds := stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), "myRoleArn", func(o *stscreds.AssumeRoleOptions) {
|
// creds := stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), "myRoleArn", func(o *stscreds.AssumeRoleOptions) {
|
||||||
// o.SerialNumber = aws.String("myTokenSerialNumber")
|
// o.SerialNumber = aws.String("myTokenSerialNumber")
|
||||||
// o.TokenProvider = stscreds.StdinTokenProvider
|
// o.TokenProvider = stscreds.StdinTokenProvider
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// cfg.Credentials = aws.NewCredentialsCache(creds)
|
// cfg.Credentials = aws.NewCredentialsCache(creds)
|
||||||
//
|
//
|
||||||
// // Create service client value configured for credentials
|
// // Create service client value configured for credentials
|
||||||
// // from assumed role.
|
// // from assumed role.
|
||||||
// svc := s3.NewFromConfig(cfg)
|
// svc := s3.NewFromConfig(cfg)
|
||||||
package stscreds
|
package stscreds
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@
|
||||||
//
|
//
|
||||||
// aws-sdk-go-v2 is the the v2 of the AWS SDK for the Go programming language.
|
// aws-sdk-go-v2 is the the v2 of the AWS SDK for the Go programming language.
|
||||||
//
|
//
|
||||||
// Getting started
|
// # Getting started
|
||||||
//
|
//
|
||||||
// The best way to get started working with the SDK is to use `go get` to add the
|
// The best way to get started working with the SDK is to use `go get` to add the
|
||||||
// SDK and desired service clients to your Go dependencies explicitly.
|
// SDK and desired service clients to your Go dependencies explicitly.
|
||||||
//
|
//
|
||||||
// go get github.com/aws/aws-sdk-go-v2
|
// go get github.com/aws/aws-sdk-go-v2
|
||||||
// go get github.com/aws/aws-sdk-go-v2/config
|
// go get github.com/aws/aws-sdk-go-v2/config
|
||||||
// go get github.com/aws/aws-sdk-go-v2/service/dynamodb
|
// go get github.com/aws/aws-sdk-go-v2/service/dynamodb
|
||||||
//
|
//
|
||||||
// Hello AWS
|
// # Hello AWS
|
||||||
//
|
//
|
||||||
// This example shows how you can use the v2 SDK to make an API request using the
|
// This example shows how you can use the v2 SDK to make an API request using the
|
||||||
// SDK's Amazon DynamoDB client.
|
// SDK's Amazon DynamoDB client.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,100 @@
|
||||||
|
# v1.13.3 (2023-04-24)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.2 (2023-04-07)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.1 (2023-03-21)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.13.0 (2023-03-14)
|
||||||
|
|
||||||
|
* **Feature**: Add flag to disable IMDSv1 fallback
|
||||||
|
|
||||||
|
# v1.12.24 (2023-03-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.23 (2023-02-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.22 (2023-02-03)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.21 (2022-12-15)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.20 (2022-12-02)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.19 (2022-10-24)
|
||||||
|
|
||||||
|
* **Bug Fix**: Fixes an issue that prevented logging of the API request or responses when the respective log modes were enabled.
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.18 (2022-10-21)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.17 (2022-09-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.16 (2022-09-14)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.15 (2022-09-02)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.14 (2022-08-31)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.13 (2022-08-29)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.12 (2022-08-11)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.11 (2022-08-09)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.10 (2022-08-08)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.9 (2022-08-01)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.8 (2022-07-05)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.7 (2022-06-29)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.6 (2022-06-07)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.12.5 (2022-05-17)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
# v1.12.4 (2022-04-25)
|
# v1.12.4 (2022-04-25)
|
||||||
|
|
||||||
* **Dependency Update**: Updated to the latest SDK module versions
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
|
||||||
|
|
@ -106,8 +106,10 @@ func New(options Options, optFns ...func(*Options)) *Client {
|
||||||
// or adding custom middleware behavior.
|
// or adding custom middleware behavior.
|
||||||
func NewFromConfig(cfg aws.Config, optFns ...func(*Options)) *Client {
|
func NewFromConfig(cfg aws.Config, optFns ...func(*Options)) *Client {
|
||||||
opts := Options{
|
opts := Options{
|
||||||
APIOptions: append([]func(*middleware.Stack) error{}, cfg.APIOptions...),
|
APIOptions: append([]func(*middleware.Stack) error{}, cfg.APIOptions...),
|
||||||
HTTPClient: cfg.HTTPClient,
|
HTTPClient: cfg.HTTPClient,
|
||||||
|
ClientLogMode: cfg.ClientLogMode,
|
||||||
|
Logger: cfg.Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Retryer != nil {
|
if cfg.Retryer != nil {
|
||||||
|
|
@ -172,6 +174,16 @@ type Options struct {
|
||||||
// The logger writer interface to write logging messages to.
|
// The logger writer interface to write logging messages to.
|
||||||
Logger logging.Logger
|
Logger logging.Logger
|
||||||
|
|
||||||
|
// Configure IMDSv1 fallback behavior. By default, the client will attempt
|
||||||
|
// to fall back to IMDSv1 as needed for backwards compatibility. When set to [aws.FalseTernary]
|
||||||
|
// the client will return any errors encountered from attempting to fetch a token
|
||||||
|
// instead of silently using the insecure data flow of IMDSv1.
|
||||||
|
//
|
||||||
|
// See [configuring IMDS] for more information.
|
||||||
|
//
|
||||||
|
// [configuring IMDS]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html
|
||||||
|
EnableFallback aws.Ternary
|
||||||
|
|
||||||
// provides the caching of API tokens used for operation calls. If unset,
|
// provides the caching of API tokens used for operation calls. If unset,
|
||||||
// the API token will not be retrieved for the operation.
|
// the API token will not be retrieved for the operation.
|
||||||
tokenProvider *tokenProvider
|
tokenProvider *tokenProvider
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,4 @@
|
||||||
package imds
|
package imds
|
||||||
|
|
||||||
// goModuleVersion is the tagged release for this module
|
// goModuleVersion is the tagged release for this module
|
||||||
const goModuleVersion = "1.12.4"
|
const goModuleVersion = "1.13.3"
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,21 @@ func addRequestMiddleware(stack *middleware.Stack,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = stack.Deserialize.Add(&smithyhttp.RequestResponseLogger{
|
||||||
|
LogRequest: options.ClientLogMode.IsRequest(),
|
||||||
|
LogRequestWithBody: options.ClientLogMode.IsRequestWithBody(),
|
||||||
|
LogResponse: options.ClientLogMode.IsResponse(),
|
||||||
|
LogResponseWithBody: options.ClientLogMode.IsResponseWithBody(),
|
||||||
|
}, middleware.After)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = addSetLoggerMiddleware(stack, options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Retry support
|
// Retry support
|
||||||
return retry.AddRetryMiddlewares(stack, retry.AddRetryMiddlewaresOptions{
|
return retry.AddRetryMiddlewares(stack, retry.AddRetryMiddlewaresOptions{
|
||||||
Retryer: options.Retryer,
|
Retryer: options.Retryer,
|
||||||
|
|
@ -93,6 +108,10 @@ func addRequestMiddleware(stack *middleware.Stack,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addSetLoggerMiddleware(stack *middleware.Stack, o Options) error {
|
||||||
|
return middleware.AddSetLoggerMiddleware(stack, o.Logger)
|
||||||
|
}
|
||||||
|
|
||||||
type serializeRequest struct {
|
type serializeRequest struct {
|
||||||
GetPath func(interface{}) (string, error)
|
GetPath func(interface{}) (string, error)
|
||||||
Method string
|
Method string
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,14 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
|
"github.com/aws/smithy-go"
|
||||||
|
"github.com/aws/smithy-go/logging"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
smithy "github.com/aws/smithy-go"
|
|
||||||
"github.com/aws/smithy-go/middleware"
|
"github.com/aws/smithy-go/middleware"
|
||||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||||
)
|
)
|
||||||
|
|
@ -68,7 +70,7 @@ func (t *tokenProvider) HandleFinalize(
|
||||||
) (
|
) (
|
||||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||||
) {
|
) {
|
||||||
if !t.enabled() {
|
if t.fallbackEnabled() && !t.enabled() {
|
||||||
// short-circuits to insecure data flow if token provider is disabled.
|
// short-circuits to insecure data flow if token provider is disabled.
|
||||||
return next.HandleFinalize(ctx, input)
|
return next.HandleFinalize(ctx, input)
|
||||||
}
|
}
|
||||||
|
|
@ -115,23 +117,15 @@ func (t *tokenProvider) HandleDeserialize(
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode == http.StatusUnauthorized { // unauthorized
|
if resp.StatusCode == http.StatusUnauthorized { // unauthorized
|
||||||
err = &retryableError{Err: err}
|
|
||||||
t.enable()
|
t.enable()
|
||||||
|
err = &retryableError{Err: err, isRetryable: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
return out, metadata, err
|
return out, metadata, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type retryableError struct {
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*retryableError) RetryableError() bool { return true }
|
|
||||||
|
|
||||||
func (e *retryableError) Error() string { return e.Err.Error() }
|
|
||||||
|
|
||||||
func (t *tokenProvider) getToken(ctx context.Context) (tok *apiToken, err error) {
|
func (t *tokenProvider) getToken(ctx context.Context) (tok *apiToken, err error) {
|
||||||
if !t.enabled() {
|
if t.fallbackEnabled() && !t.enabled() {
|
||||||
return nil, &bypassTokenRetrievalError{
|
return nil, &bypassTokenRetrievalError{
|
||||||
Err: fmt.Errorf("cannot get API token, provider disabled"),
|
Err: fmt.Errorf("cannot get API token, provider disabled"),
|
||||||
}
|
}
|
||||||
|
|
@ -147,7 +141,7 @@ func (t *tokenProvider) getToken(ctx context.Context) (tok *apiToken, err error)
|
||||||
|
|
||||||
tok, err = t.updateToken(ctx)
|
tok, err = t.updateToken(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot get API token, %w", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return tok, nil
|
return tok, nil
|
||||||
|
|
@ -167,17 +161,19 @@ func (t *tokenProvider) updateToken(ctx context.Context) (*apiToken, error) {
|
||||||
TokenTTL: t.tokenTTL,
|
TokenTTL: t.tokenTTL,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// change the disabled flag on token provider to true, when error is request timeout error.
|
|
||||||
var statusErr interface{ HTTPStatusCode() int }
|
var statusErr interface{ HTTPStatusCode() int }
|
||||||
if errors.As(err, &statusErr) {
|
if errors.As(err, &statusErr) {
|
||||||
switch statusErr.HTTPStatusCode() {
|
switch statusErr.HTTPStatusCode() {
|
||||||
|
// Disable future get token if failed because of 403, 404, or 405
|
||||||
// Disable get token if failed because of 403, 404, or 405
|
|
||||||
case http.StatusForbidden,
|
case http.StatusForbidden,
|
||||||
http.StatusNotFound,
|
http.StatusNotFound,
|
||||||
http.StatusMethodNotAllowed:
|
http.StatusMethodNotAllowed:
|
||||||
|
|
||||||
t.disable()
|
if t.fallbackEnabled() {
|
||||||
|
logger := middleware.GetLogger(ctx)
|
||||||
|
logger.Logf(logging.Warn, "falling back to IMDSv1: %v", err)
|
||||||
|
t.disable()
|
||||||
|
}
|
||||||
|
|
||||||
// 400 errors are terminal, and need to be upstreamed
|
// 400 errors are terminal, and need to be upstreamed
|
||||||
case http.StatusBadRequest:
|
case http.StatusBadRequest:
|
||||||
|
|
@ -192,8 +188,17 @@ func (t *tokenProvider) updateToken(ctx context.Context) (*apiToken, error) {
|
||||||
atomic.StoreUint32(&t.disabled, 1)
|
atomic.StoreUint32(&t.disabled, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token couldn't be retrieved, but bypass this, and allow the
|
if !t.fallbackEnabled() {
|
||||||
// request to continue.
|
// NOTE: getToken() is an implementation detail of some outer operation
|
||||||
|
// (e.g. GetMetadata). It has its own retries that have already been exhausted.
|
||||||
|
// Mark the underlying error as a terminal error.
|
||||||
|
err = &retryableError{Err: err, isRetryable: false}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token couldn't be retrieved, fallback to IMDSv1 insecure flow for this request
|
||||||
|
// and allow the request to proceed. Future requests _may_ re-attempt fetching a
|
||||||
|
// token if not disabled.
|
||||||
return nil, &bypassTokenRetrievalError{Err: err}
|
return nil, &bypassTokenRetrievalError{Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,21 +211,21 @@ func (t *tokenProvider) updateToken(ctx context.Context) (*apiToken, error) {
|
||||||
return tok, nil
|
return tok, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type bypassTokenRetrievalError struct {
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *bypassTokenRetrievalError) Error() string {
|
|
||||||
return fmt.Sprintf("bypass token retrieval, %v", e.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *bypassTokenRetrievalError) Unwrap() error { return e.Err }
|
|
||||||
|
|
||||||
// enabled returns if the token provider is current enabled or not.
|
// enabled returns if the token provider is current enabled or not.
|
||||||
func (t *tokenProvider) enabled() bool {
|
func (t *tokenProvider) enabled() bool {
|
||||||
return atomic.LoadUint32(&t.disabled) == 0
|
return atomic.LoadUint32(&t.disabled) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fallbackEnabled returns false if EnableFallback is [aws.FalseTernary], true otherwise
|
||||||
|
func (t *tokenProvider) fallbackEnabled() bool {
|
||||||
|
switch t.client.options.EnableFallback {
|
||||||
|
case aws.FalseTernary:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// disable disables the token provider and it will no longer attempt to inject
|
// disable disables the token provider and it will no longer attempt to inject
|
||||||
// the token, nor request updates.
|
// the token, nor request updates.
|
||||||
func (t *tokenProvider) disable() {
|
func (t *tokenProvider) disable() {
|
||||||
|
|
@ -235,3 +240,22 @@ func (t *tokenProvider) enable() {
|
||||||
t.tokenMux.Unlock()
|
t.tokenMux.Unlock()
|
||||||
atomic.StoreUint32(&t.disabled, 0)
|
atomic.StoreUint32(&t.disabled, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type bypassTokenRetrievalError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *bypassTokenRetrievalError) Error() string {
|
||||||
|
return fmt.Sprintf("bypass token retrieval, %v", e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *bypassTokenRetrievalError) Unwrap() error { return e.Err }
|
||||||
|
|
||||||
|
type retryableError struct {
|
||||||
|
Err error
|
||||||
|
isRetryable bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *retryableError) RetryableError() bool { return e.isRetryable }
|
||||||
|
|
||||||
|
func (e *retryableError) Error() string { return e.Err.Error() }
|
||||||
|
|
|
||||||
385
vendor/github.com/aws/aws-sdk-go-v2/feature/s3/manager/CHANGELOG.md
generated
vendored
Normal file
385
vendor/github.com/aws/aws-sdk-go-v2/feature/s3/manager/CHANGELOG.md
generated
vendored
Normal file
|
|
@ -0,0 +1,385 @@
|
||||||
|
# v1.11.67 (2023-05-09)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.66 (2023-05-08)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.65 (2023-05-04)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.64 (2023-04-24)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.63 (2023-04-19)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.62 (2023-04-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.61 (2023-04-07)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.60 (2023-03-31)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.59 (2023-03-21)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.58 (2023-03-16)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.57 (2023-03-14)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.56 (2023-03-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.55 (2023-02-22)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.54 (2023-02-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.53 (2023-02-15)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.52 (2023-02-14)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.51 (2023-02-03)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.50 (2023-02-01)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.49 (2023-01-25)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.48 (2023-01-23)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.47 (2023-01-05)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.46 (2022-12-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.45 (2022-12-19)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.44 (2022-12-15)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.43 (2022-12-02)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.42 (2022-11-22)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.41 (2022-11-17)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.40 (2022-11-16)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.39 (2022-11-11)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.38 (2022-11-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.37 (2022-10-24)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.36 (2022-10-21)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.35 (2022-10-19)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.34 (2022-09-30)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.33 (2022-09-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.32 (2022-09-14)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.31 (2022-09-02)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.30 (2022-08-31)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.29 (2022-08-30)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.28 (2022-08-29)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.27 (2022-08-15)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.26 (2022-08-14)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.25 (2022-08-11)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.24 (2022-08-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.23 (2022-08-09)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.22 (2022-08-08)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.21 (2022-08-01)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.20 (2022-07-11)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.19 (2022-07-05)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.18 (2022-07-01)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.17 (2022-06-29)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.16 (2022-06-16)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.15 (2022-06-07)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.14 (2022-05-26)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.13 (2022-05-25)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.12 (2022-05-17)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.11 (2022-05-16)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.10 (2022-05-09)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.9 (2022-05-06)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.8 (2022-05-03)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.7 (2022-04-27)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.6 (2022-04-25)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.5 (2022-04-12)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.4 (2022-04-07)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.3 (2022-03-30)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.2 (2022-03-24)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.1 (2022-03-23)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.11.0 (2022-03-08)
|
||||||
|
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.10.0 (2022-02-24)
|
||||||
|
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.9.1 (2022-01-28)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.9.0 (2022-01-14)
|
||||||
|
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.8.0 (2022-01-07)
|
||||||
|
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.7.5 (2021-12-21)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.7.4 (2021-12-02)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.7.3 (2021-11-30)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.7.2 (2021-11-19)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.7.1 (2021-11-12)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.7.0 (2021-11-06)
|
||||||
|
|
||||||
|
* **Feature**: The SDK now supports configuration of FIPS and DualStack endpoints using environment variables, shared configuration, or programmatically.
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.6.0 (2021-10-21)
|
||||||
|
|
||||||
|
* **Feature**: Updated to latest version
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.5.4 (2021-10-11)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.5.3 (2021-09-17)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.5.2 (2021-09-10)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.5.1 (2021-09-02)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.5.0 (2021-08-27)
|
||||||
|
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.4.1 (2021-08-19)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.4.0 (2021-08-04)
|
||||||
|
|
||||||
|
* **Feature**: adds error handling for defered close calls
|
||||||
|
* **Dependency Update**: Updated `github.com/aws/smithy-go` to latest version.
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.3.2 (2021-07-15)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.3.1 (2021-07-01)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.3.0 (2021-06-25)
|
||||||
|
|
||||||
|
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.2.3 (2021-06-04)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.2.2 (2021-05-25)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.2.1 (2021-05-20)
|
||||||
|
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
|
# v1.2.0 (2021-05-14)
|
||||||
|
|
||||||
|
* **Feature**: Constant has been added to modules to enable runtime version inspection for reporting.
|
||||||
|
* **Dependency Update**: Updated to the latest SDK module versions
|
||||||
|
|
||||||
202
vendor/github.com/aws/aws-sdk-go-v2/feature/s3/manager/LICENSE.txt
generated
vendored
Normal file
202
vendor/github.com/aws/aws-sdk-go-v2/feature/s3/manager/LICENSE.txt
generated
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package manager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeleteObjectsAPIClient is an S3 API client that can invoke the DeleteObjects operation.
|
||||||
|
type DeleteObjectsAPIClient interface {
|
||||||
|
DeleteObjects(context.Context, *s3.DeleteObjectsInput, ...func(*s3.Options)) (*s3.DeleteObjectsOutput, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadAPIClient is an S3 API client that can invoke the GetObject operation.
|
||||||
|
type DownloadAPIClient interface {
|
||||||
|
GetObject(context.Context, *s3.GetObjectInput, ...func(*s3.Options)) (*s3.GetObjectOutput, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeadBucketAPIClient is an S3 API client that can invoke the HeadBucket operation.
|
||||||
|
type HeadBucketAPIClient interface {
|
||||||
|
HeadBucket(context.Context, *s3.HeadBucketInput, ...func(*s3.Options)) (*s3.HeadBucketOutput, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListObjectsV2APIClient is an S3 API client that can invoke the ListObjectV2 operation.
|
||||||
|
type ListObjectsV2APIClient interface {
|
||||||
|
ListObjectsV2(context.Context, *s3.ListObjectsV2Input, ...func(*s3.Options)) (*s3.ListObjectsV2Output, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadAPIClient is an S3 API client that can invoke PutObject, UploadPart, CreateMultipartUpload,
|
||||||
|
// CompleteMultipartUpload, and AbortMultipartUpload operations.
|
||||||
|
type UploadAPIClient interface {
|
||||||
|
PutObject(context.Context, *s3.PutObjectInput, ...func(*s3.Options)) (*s3.PutObjectOutput, error)
|
||||||
|
UploadPart(context.Context, *s3.UploadPartInput, ...func(*s3.Options)) (*s3.UploadPartOutput, error)
|
||||||
|
CreateMultipartUpload(context.Context, *s3.CreateMultipartUploadInput, ...func(*s3.Options)) (*s3.CreateMultipartUploadOutput, error)
|
||||||
|
CompleteMultipartUpload(context.Context, *s3.CompleteMultipartUploadInput, ...func(*s3.Options)) (*s3.CompleteMultipartUploadOutput, error)
|
||||||
|
AbortMultipartUpload(context.Context, *s3.AbortMultipartUploadInput, ...func(*s3.Options)) (*s3.AbortMultipartUploadOutput, error)
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/aws/aws-sdk-go/aws/arn"
|
"github.com/aws/aws-sdk-go-v2/aws/arn"
|
||||||
)
|
)
|
||||||
|
|
||||||
func validateSupportedARNType(bucket string) error {
|
func validateSupportedARNType(bucket string) error {
|
||||||
139
vendor/github.com/aws/aws-sdk-go-v2/feature/s3/manager/bucket_region.go
generated
vendored
Normal file
139
vendor/github.com/aws/aws-sdk-go-v2/feature/s3/manager/bucket_region.go
generated
vendored
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
package manager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
|
"github.com/aws/smithy-go/middleware"
|
||||||
|
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
const bucketRegionHeader = "X-Amz-Bucket-Region"
|
||||||
|
|
||||||
|
// GetBucketRegion will attempt to get the region for a bucket using the
|
||||||
|
// client's configured region to determine which AWS partition to perform the query on.
|
||||||
|
//
|
||||||
|
// The request will not be signed, and will not use your AWS credentials.
|
||||||
|
//
|
||||||
|
// A BucketNotFound error will be returned if the bucket does not exist in the
|
||||||
|
// AWS partition the client region belongs to.
|
||||||
|
//
|
||||||
|
// For example to get the region of a bucket which exists in "eu-central-1"
|
||||||
|
// you could provide a region hint of "us-west-2".
|
||||||
|
//
|
||||||
|
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
||||||
|
// if err != nil {
|
||||||
|
// log.Println("error:", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// bucket := "my-bucket"
|
||||||
|
// region, err := manager.GetBucketRegion(ctx, s3.NewFromConfig(cfg), bucket)
|
||||||
|
// if err != nil {
|
||||||
|
// var bnf manager.BucketNotFound
|
||||||
|
// if errors.As(err, &bnf) {
|
||||||
|
// fmt.Fprintf(os.Stderr, "unable to find bucket %s's region\n", bucket)
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// fmt.Printf("Bucket %s is in %s region\n", bucket, region)
|
||||||
|
//
|
||||||
|
// By default the request will be made to the Amazon S3 endpoint using the virtual-hosted-style addressing.
|
||||||
|
//
|
||||||
|
// bucketname.s3.us-west-2.amazonaws.com/
|
||||||
|
//
|
||||||
|
// To configure the GetBucketRegion to make a request via the Amazon
|
||||||
|
// S3 FIPS endpoints directly when a FIPS region name is not available, (e.g.
|
||||||
|
// fips-us-gov-west-1) set the EndpointResolver on the config or client the
|
||||||
|
// utility is called with.
|
||||||
|
//
|
||||||
|
// cfg, err := config.LoadDefaultConfig(context.TODO(),
|
||||||
|
// config.WithEndpointResolver(
|
||||||
|
// aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
|
||||||
|
// return aws.Endpoint{URL: "https://s3-fips.us-west-2.amazonaws.com"}, nil
|
||||||
|
// }),
|
||||||
|
// )
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
func GetBucketRegion(ctx context.Context, client HeadBucketAPIClient, bucket string, optFns ...func(*s3.Options)) (string, error) {
|
||||||
|
var captureBucketRegion deserializeBucketRegion
|
||||||
|
|
||||||
|
clientOptionFns := make([]func(*s3.Options), len(optFns)+1)
|
||||||
|
clientOptionFns[0] = func(options *s3.Options) {
|
||||||
|
options.Credentials = aws.AnonymousCredentials{}
|
||||||
|
options.APIOptions = append(options.APIOptions, captureBucketRegion.RegisterMiddleware)
|
||||||
|
}
|
||||||
|
copy(clientOptionFns[1:], optFns)
|
||||||
|
|
||||||
|
_, err := client.HeadBucket(ctx, &s3.HeadBucketInput{
|
||||||
|
Bucket: aws.String(bucket),
|
||||||
|
}, clientOptionFns...)
|
||||||
|
if len(captureBucketRegion.BucketRegion) == 0 && err != nil {
|
||||||
|
var httpStatusErr interface {
|
||||||
|
HTTPStatusCode() int
|
||||||
|
}
|
||||||
|
if !errors.As(err, &httpStatusErr) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if httpStatusErr.HTTPStatusCode() == http.StatusNotFound {
|
||||||
|
return "", &bucketNotFound{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return captureBucketRegion.BucketRegion, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type deserializeBucketRegion struct {
|
||||||
|
BucketRegion string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deserializeBucketRegion) RegisterMiddleware(stack *middleware.Stack) error {
|
||||||
|
return stack.Deserialize.Add(d, middleware.After)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deserializeBucketRegion) ID() string {
|
||||||
|
return "DeserializeBucketRegion"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deserializeBucketRegion) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) (
|
||||||
|
out middleware.DeserializeOutput, metadata middleware.Metadata, err error,
|
||||||
|
) {
|
||||||
|
out, metadata, err = next.HandleDeserialize(ctx, in)
|
||||||
|
if err != nil {
|
||||||
|
return out, metadata, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, ok := out.RawResponse.(*smithyhttp.Response)
|
||||||
|
if !ok {
|
||||||
|
return out, metadata, fmt.Errorf("unknown transport type %T", out.RawResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.BucketRegion = resp.Header.Get(bucketRegionHeader)
|
||||||
|
|
||||||
|
return out, metadata, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// BucketNotFound indicates the bucket was not found in the partition when calling GetBucketRegion.
|
||||||
|
type BucketNotFound interface {
|
||||||
|
error
|
||||||
|
|
||||||
|
isBucketNotFound()
|
||||||
|
}
|
||||||
|
|
||||||
|
type bucketNotFound struct{}
|
||||||
|
|
||||||
|
func (b *bucketNotFound) Error() string {
|
||||||
|
return "bucket not found"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bucketNotFound) isBucketNotFound() {}
|
||||||
|
|
||||||
|
var _ BucketNotFound = (*bucketNotFound)(nil)
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/internal/sdkio"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// BufferedReadSeeker is buffered io.ReadSeeker
|
// BufferedReadSeeker is buffered io.ReadSeeker
|
||||||
|
|
@ -72,7 +70,7 @@ func (b *BufferedReadSeeker) Seek(offset int64, whence int) (int64, error) {
|
||||||
// ReadAt will read up to len(p) bytes at the given file offset.
|
// ReadAt will read up to len(p) bytes at the given file offset.
|
||||||
// This will result in the buffer being cleared.
|
// This will result in the buffer being cleared.
|
||||||
func (b *BufferedReadSeeker) ReadAt(p []byte, off int64) (int, error) {
|
func (b *BufferedReadSeeker) ReadAt(p []byte, off int64) (int, error) {
|
||||||
_, err := b.Seek(off, sdkio.SeekStart)
|
_, err := b.Seek(off, io.SeekStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
// +build !windows
|
||||||
|
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
func defaultUploadBufferProvider() ReadSeekerWriteToProvider {
|
func defaultUploadBufferProvider() ReadSeekerWriteToProvider {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
func defaultUploadBufferProvider() ReadSeekerWriteToProvider {
|
func defaultUploadBufferProvider() ReadSeekerWriteToProvider {
|
||||||
return NewBufferedReadSeekerWriteToPool(1024 * 1024)
|
return NewBufferedReadSeekerWriteToPool(1024 * 1024)
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
// +build !windows
|
||||||
|
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
func defaultDownloadBufferProvider() WriterReadFromProvider {
|
func defaultDownloadBufferProvider() WriterReadFromProvider {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
func defaultDownloadBufferProvider() WriterReadFromProvider {
|
func defaultDownloadBufferProvider() WriterReadFromProvider {
|
||||||
return NewPooledBufferedWriterReadFromProvider(1024 * 1024)
|
return NewPooledBufferedWriterReadFromProvider(1024 * 1024)
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Package manager provides utilities to upload and download objects from
|
||||||
|
// S3 concurrently. Helpful for when working with large objects.
|
||||||
|
package manager
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -8,15 +10,15 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go-v2/aws/middleware"
|
||||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
"github.com/aws/aws-sdk-go-v2/internal/awsutil"
|
||||||
"github.com/aws/aws-sdk-go/aws/client"
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
"github.com/aws/aws-sdk-go/aws/request"
|
"github.com/aws/smithy-go/logging"
|
||||||
"github.com/aws/aws-sdk-go/service/s3"
|
|
||||||
"github.com/aws/aws-sdk-go/service/s3/s3iface"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const userAgentKey = "s3-transfer"
|
||||||
|
|
||||||
// DefaultDownloadPartSize is the default range of bytes to get at a time when
|
// DefaultDownloadPartSize is the default range of bytes to get at a time when
|
||||||
// using Download().
|
// using Download().
|
||||||
const DefaultDownloadPartSize = 1024 * 1024 * 5
|
const DefaultDownloadPartSize = 1024 * 1024 * 5
|
||||||
|
|
@ -25,6 +27,9 @@ const DefaultDownloadPartSize = 1024 * 1024 * 5
|
||||||
// when using Download().
|
// when using Download().
|
||||||
const DefaultDownloadConcurrency = 5
|
const DefaultDownloadConcurrency = 5
|
||||||
|
|
||||||
|
// DefaultPartBodyMaxRetries is the default number of retries to make when a part fails to download.
|
||||||
|
const DefaultPartBodyMaxRetries = 3
|
||||||
|
|
||||||
type errReadingBody struct {
|
type errReadingBody struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +53,15 @@ type Downloader struct {
|
||||||
// PartSize is ignored if the Range input parameter is provided.
|
// PartSize is ignored if the Range input parameter is provided.
|
||||||
PartSize int64
|
PartSize int64
|
||||||
|
|
||||||
|
// PartBodyMaxRetries is the number of retry attempts to make for failed part downloads.
|
||||||
|
PartBodyMaxRetries int
|
||||||
|
|
||||||
|
// Logger to send logging messages to
|
||||||
|
Logger logging.Logger
|
||||||
|
|
||||||
|
// Enable Logging of part download retry attempts
|
||||||
|
LogInterruptedDownloads bool
|
||||||
|
|
||||||
// The number of goroutines to spin up in parallel when sending parts.
|
// The number of goroutines to spin up in parallel when sending parts.
|
||||||
// If this is set to zero, the DefaultDownloadConcurrency value will be used.
|
// If this is set to zero, the DefaultDownloadConcurrency value will be used.
|
||||||
//
|
//
|
||||||
|
|
@ -57,11 +71,11 @@ type Downloader struct {
|
||||||
Concurrency int
|
Concurrency int
|
||||||
|
|
||||||
// An S3 client to use when performing downloads.
|
// An S3 client to use when performing downloads.
|
||||||
S3 s3iface.S3API
|
S3 DownloadAPIClient
|
||||||
|
|
||||||
// List of request options that will be passed down to individual API
|
// List of client options that will be passed down to individual API
|
||||||
// operation requests made by the downloader.
|
// operation requests made by the downloader.
|
||||||
RequestOptions []request.Option
|
ClientOptions []func(*s3.Options)
|
||||||
|
|
||||||
// Defines the buffer strategy used when downloading a part.
|
// Defines the buffer strategy used when downloading a part.
|
||||||
//
|
//
|
||||||
|
|
@ -72,10 +86,10 @@ type Downloader struct {
|
||||||
BufferProvider WriterReadFromProvider
|
BufferProvider WriterReadFromProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDownloaderRequestOptions appends to the Downloader's API request options.
|
// WithDownloaderClientOptions appends to the Downloader's API request options.
|
||||||
func WithDownloaderRequestOptions(opts ...request.Option) func(*Downloader) {
|
func WithDownloaderClientOptions(opts ...func(*s3.Options)) func(*Downloader) {
|
||||||
return func(d *Downloader) {
|
return func(d *Downloader) {
|
||||||
d.RequestOptions = append(d.RequestOptions, opts...)
|
d.ClientOptions = append(d.ClientOptions, opts...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,26 +101,29 @@ func WithDownloaderRequestOptions(opts ...request.Option) func(*Downloader) {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// // The session the S3 Downloader will use
|
// // Load AWS Config
|
||||||
// sess := session.Must(session.NewSession())
|
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// // Create a downloader with the session and default options
|
// // Create an S3 client using the loaded configuration
|
||||||
// downloader := s3manager.NewDownloader(sess)
|
// s3.NewFromConfig(cfg)
|
||||||
//
|
//
|
||||||
// // Create a downloader with the session and custom options
|
// // Create a downloader passing it the S3 client
|
||||||
// downloader := s3manager.NewDownloader(sess, func(d *s3manager.Downloader) {
|
// downloader := manager.NewDownloader(s3.NewFromConfig(cfg))
|
||||||
// d.PartSize = 64 * 1024 * 1024 // 64MB per part
|
//
|
||||||
|
// // Create a downloader with the client and custom downloader options
|
||||||
|
// downloader := manager.NewDownloader(client, func(d *manager.Downloader) {
|
||||||
|
// d.PartSize = 64 * 1024 * 1024 // 64MB per part
|
||||||
// })
|
// })
|
||||||
func NewDownloader(c client.ConfigProvider, options ...func(*Downloader)) *Downloader {
|
func NewDownloader(c DownloadAPIClient, options ...func(*Downloader)) *Downloader {
|
||||||
return newDownloader(s3.New(c), options...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDownloader(client s3iface.S3API, options ...func(*Downloader)) *Downloader {
|
|
||||||
d := &Downloader{
|
d := &Downloader{
|
||||||
S3: client,
|
S3: c,
|
||||||
PartSize: DefaultDownloadPartSize,
|
PartSize: DefaultDownloadPartSize,
|
||||||
Concurrency: DefaultDownloadConcurrency,
|
PartBodyMaxRetries: DefaultPartBodyMaxRetries,
|
||||||
BufferProvider: defaultDownloadBufferProvider(),
|
Concurrency: DefaultDownloadConcurrency,
|
||||||
|
BufferProvider: defaultDownloadBufferProvider(),
|
||||||
}
|
}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(d)
|
option(d)
|
||||||
|
|
@ -115,58 +132,7 @@ func newDownloader(client s3iface.S3API, options ...func(*Downloader)) *Download
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDownloaderWithClient creates a new Downloader instance to downloads
|
// Download downloads an object in S3 and writes the payload into w
|
||||||
// objects from S3 in concurrent chunks. Pass in additional functional
|
|
||||||
// options to customize the downloader behavior. Requires a S3 service client
|
|
||||||
// to make S3 API calls.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// // The session the S3 Downloader will use
|
|
||||||
// sess := session.Must(session.NewSession())
|
|
||||||
//
|
|
||||||
// // The S3 client the S3 Downloader will use
|
|
||||||
// s3Svc := s3.New(sess)
|
|
||||||
//
|
|
||||||
// // Create a downloader with the s3 client and default options
|
|
||||||
// downloader := s3manager.NewDownloaderWithClient(s3Svc)
|
|
||||||
//
|
|
||||||
// // Create a downloader with the s3 client and custom options
|
|
||||||
// downloader := s3manager.NewDownloaderWithClient(s3Svc, func(d *s3manager.Downloader) {
|
|
||||||
// d.PartSize = 64 * 1024 * 1024 // 64MB per part
|
|
||||||
// })
|
|
||||||
func NewDownloaderWithClient(svc s3iface.S3API, options ...func(*Downloader)) *Downloader {
|
|
||||||
return newDownloader(svc, options...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type maxRetrier interface {
|
|
||||||
MaxRetries() int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download downloads an object in S3 and writes the payload into w using
|
|
||||||
// concurrent GET requests. The n int64 returned is the size of the object downloaded
|
|
||||||
// in bytes.
|
|
||||||
//
|
|
||||||
// Additional functional options can be provided to configure the individual
|
|
||||||
// download. These options are copies of the Downloader instance Download is called from.
|
|
||||||
// Modifying the options will not impact the original Downloader instance.
|
|
||||||
//
|
|
||||||
// It is safe to call this method concurrently across goroutines.
|
|
||||||
//
|
|
||||||
// The w io.WriterAt can be satisfied by an os.File to do multipart concurrent
|
|
||||||
// downloads, or in memory []byte wrapper using aws.WriteAtBuffer.
|
|
||||||
//
|
|
||||||
// Specifying a Downloader.Concurrency of 1 will cause the Downloader to
|
|
||||||
// download the parts from S3 sequentially.
|
|
||||||
//
|
|
||||||
// If the GetObjectInput's Range value is provided that will cause the downloader
|
|
||||||
// to perform a single GetObjectInput request for that object's range. This will
|
|
||||||
// caused the part size, and concurrency configurations to be ignored.
|
|
||||||
func (d Downloader) Download(w io.WriterAt, input *s3.GetObjectInput, options ...func(*Downloader)) (n int64, err error) {
|
|
||||||
return d.DownloadWithContext(aws.BackgroundContext(), w, input, options...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DownloadWithContext downloads an object in S3 and writes the payload into w
|
|
||||||
// using concurrent GET requests. The n int64 returned is the size of the object downloaded
|
// using concurrent GET requests. The n int64 returned is the size of the object downloaded
|
||||||
// in bytes.
|
// in bytes.
|
||||||
//
|
//
|
||||||
|
|
@ -179,11 +145,25 @@ func (d Downloader) Download(w io.WriterAt, input *s3.GetObjectInput, options ..
|
||||||
// Additional functional options can be provided to configure the individual
|
// Additional functional options can be provided to configure the individual
|
||||||
// download. These options are copies of the Downloader instance Download is
|
// download. These options are copies of the Downloader instance Download is
|
||||||
// called from. Modifying the options will not impact the original Downloader
|
// called from. Modifying the options will not impact the original Downloader
|
||||||
// instance. Use the WithDownloaderRequestOptions helper function to pass in request
|
// instance. Use the WithDownloaderClientOptions helper function to pass in request
|
||||||
// options that will be applied to all API operations made with this downloader.
|
// options that will be applied to all API operations made with this downloader.
|
||||||
//
|
//
|
||||||
// The w io.WriterAt can be satisfied by an os.File to do multipart concurrent
|
// The w io.WriterAt can be satisfied by an os.File to do multipart concurrent
|
||||||
// downloads, or in memory []byte wrapper using aws.WriteAtBuffer.
|
// downloads, or in memory []byte wrapper using aws.WriteAtBuffer. In case you download
|
||||||
|
// files into memory do not forget to pre-allocate memory to avoid additional allocations
|
||||||
|
// and GC runs.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // pre-allocate in memory buffer, where headObject type is *s3.HeadObjectOutput
|
||||||
|
// buf := make([]byte, int(headObject.ContentLength))
|
||||||
|
// // wrap with aws.WriteAtBuffer
|
||||||
|
// w := s3manager.NewWriteAtBuffer(buf)
|
||||||
|
// // download file into the memory
|
||||||
|
// numBytesDownloaded, err := downloader.Download(ctx, w, &s3.GetObjectInput{
|
||||||
|
// Bucket: aws.String(bucket),
|
||||||
|
// Key: aws.String(item),
|
||||||
|
// })
|
||||||
//
|
//
|
||||||
// Specifying a Downloader.Concurrency of 1 will cause the Downloader to
|
// Specifying a Downloader.Concurrency of 1 will cause the Downloader to
|
||||||
// download the parts from S3 sequentially.
|
// download the parts from S3 sequentially.
|
||||||
|
|
@ -193,21 +173,29 @@ func (d Downloader) Download(w io.WriterAt, input *s3.GetObjectInput, options ..
|
||||||
// If the GetObjectInput's Range value is provided that will cause the downloader
|
// If the GetObjectInput's Range value is provided that will cause the downloader
|
||||||
// to perform a single GetObjectInput request for that object's range. This will
|
// to perform a single GetObjectInput request for that object's range. This will
|
||||||
// caused the part size, and concurrency configurations to be ignored.
|
// caused the part size, and concurrency configurations to be ignored.
|
||||||
func (d Downloader) DownloadWithContext(ctx aws.Context, w io.WriterAt, input *s3.GetObjectInput, options ...func(*Downloader)) (n int64, err error) {
|
func (d Downloader) Download(ctx context.Context, w io.WriterAt, input *s3.GetObjectInput, options ...func(*Downloader)) (n int64, err error) {
|
||||||
if err := validateSupportedARNType(aws.StringValue(input.Bucket)); err != nil {
|
if err := validateSupportedARNType(aws.ToString(input.Bucket)); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
impl := downloader{w: w, in: input, cfg: d, ctx: ctx}
|
impl := downloader{w: w, in: input, cfg: d, ctx: ctx}
|
||||||
|
|
||||||
|
// Copy ClientOptions
|
||||||
|
clientOptions := make([]func(*s3.Options), 0, len(impl.cfg.ClientOptions)+1)
|
||||||
|
clientOptions = append(clientOptions, func(o *s3.Options) {
|
||||||
|
o.APIOptions = append(o.APIOptions, middleware.AddSDKAgentKey(middleware.FeatureMetadata, userAgentKey))
|
||||||
|
})
|
||||||
|
clientOptions = append(clientOptions, impl.cfg.ClientOptions...)
|
||||||
|
impl.cfg.ClientOptions = clientOptions
|
||||||
|
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(&impl.cfg)
|
option(&impl.cfg)
|
||||||
}
|
}
|
||||||
impl.cfg.RequestOptions = append(impl.cfg.RequestOptions, request.WithAppendUserAgent("S3Manager"))
|
|
||||||
|
|
||||||
if s, ok := d.S3.(maxRetrier); ok {
|
// Ensures we don't need nil checks later on
|
||||||
impl.partBodyMaxRetries = s.MaxRetries()
|
impl.cfg.Logger = logging.WithContext(ctx, impl.cfg.Logger)
|
||||||
}
|
|
||||||
|
impl.partBodyMaxRetries = d.PartBodyMaxRetries
|
||||||
|
|
||||||
impl.totalBytes = -1
|
impl.totalBytes = -1
|
||||||
if impl.cfg.Concurrency == 0 {
|
if impl.cfg.Concurrency == 0 {
|
||||||
|
|
@ -221,70 +209,9 @@ func (d Downloader) DownloadWithContext(ctx aws.Context, w io.WriterAt, input *s
|
||||||
return impl.download()
|
return impl.download()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadWithIterator will download a batched amount of objects in S3 and writes them
|
|
||||||
// to the io.WriterAt specificed in the iterator.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// svc := s3manager.NewDownloader(session)
|
|
||||||
//
|
|
||||||
// fooFile, err := os.Open("/tmp/foo.file")
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// barFile, err := os.Open("/tmp/bar.file")
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// objects := []s3manager.BatchDownloadObject {
|
|
||||||
// {
|
|
||||||
// Object: &s3.GetObjectInput {
|
|
||||||
// Bucket: aws.String("bucket"),
|
|
||||||
// Key: aws.String("foo"),
|
|
||||||
// },
|
|
||||||
// Writer: fooFile,
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// Object: &s3.GetObjectInput {
|
|
||||||
// Bucket: aws.String("bucket"),
|
|
||||||
// Key: aws.String("bar"),
|
|
||||||
// },
|
|
||||||
// Writer: barFile,
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// iter := &s3manager.DownloadObjectsIterator{Objects: objects}
|
|
||||||
// if err := svc.DownloadWithIterator(aws.BackgroundContext(), iter); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
func (d Downloader) DownloadWithIterator(ctx aws.Context, iter BatchDownloadIterator, opts ...func(*Downloader)) error {
|
|
||||||
var errs []Error
|
|
||||||
for iter.Next() {
|
|
||||||
object := iter.DownloadObject()
|
|
||||||
if _, err := d.DownloadWithContext(ctx, object.Writer, object.Object, opts...); err != nil {
|
|
||||||
errs = append(errs, newError(err, object.Object.Bucket, object.Object.Key))
|
|
||||||
}
|
|
||||||
|
|
||||||
if object.After == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := object.After(); err != nil {
|
|
||||||
errs = append(errs, newError(err, object.Object.Bucket, object.Object.Key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return NewBatchError("BatchedDownloadIncomplete", "some objects have failed to download.", errs)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// downloader is the implementation structure used internally by Downloader.
|
// downloader is the implementation structure used internally by Downloader.
|
||||||
type downloader struct {
|
type downloader struct {
|
||||||
ctx aws.Context
|
ctx context.Context
|
||||||
cfg Downloader
|
cfg Downloader
|
||||||
|
|
||||||
in *s3.GetObjectInput
|
in *s3.GetObjectInput
|
||||||
|
|
@ -307,7 +234,7 @@ func (d *downloader) download() (n int64, err error) {
|
||||||
// If range is specified fall back to single download of that range
|
// If range is specified fall back to single download of that range
|
||||||
// this enables the functionality of ranged gets with the downloader but
|
// this enables the functionality of ranged gets with the downloader but
|
||||||
// at the cost of no multipart downloads.
|
// at the cost of no multipart downloads.
|
||||||
if rng := aws.StringValue(d.in.Range); len(rng) > 0 {
|
if rng := aws.ToString(d.in.Range); len(rng) > 0 {
|
||||||
d.downloadRange(rng)
|
d.downloadRange(rng)
|
||||||
return d.written, d.err
|
return d.written, d.err
|
||||||
}
|
}
|
||||||
|
|
@ -349,9 +276,13 @@ func (d *downloader) download() (n int64, err error) {
|
||||||
// keep grabbing chunks of data until the range of bytes specified in
|
// keep grabbing chunks of data until the range of bytes specified in
|
||||||
// the request is out of range of the content. Once, this happens, a
|
// the request is out of range of the content. Once, this happens, a
|
||||||
// 416 should occur.
|
// 416 should occur.
|
||||||
e, ok := d.err.(awserr.RequestFailure)
|
var responseError interface {
|
||||||
if ok && e.StatusCode() == http.StatusRequestedRangeNotSatisfiable {
|
HTTPStatusCode() int
|
||||||
d.err = nil
|
}
|
||||||
|
if errors.As(d.err, &responseError) {
|
||||||
|
if responseError.HTTPStatusCode() == http.StatusRequestedRangeNotSatisfiable {
|
||||||
|
d.err = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -419,16 +350,16 @@ func (d *downloader) downloadRange(rng string) {
|
||||||
|
|
||||||
// downloadChunk downloads the chunk from s3
|
// downloadChunk downloads the chunk from s3
|
||||||
func (d *downloader) downloadChunk(chunk dlchunk) error {
|
func (d *downloader) downloadChunk(chunk dlchunk) error {
|
||||||
in := &s3.GetObjectInput{}
|
var params s3.GetObjectInput
|
||||||
awsutil.Copy(in, d.in)
|
awsutil.Copy(¶ms, d.in)
|
||||||
|
|
||||||
// Get the next byte range of data
|
// Get the next byte range of data
|
||||||
in.Range = aws.String(chunk.ByteRange())
|
params.Range = aws.String(chunk.ByteRange())
|
||||||
|
|
||||||
var n int64
|
var n int64
|
||||||
var err error
|
var err error
|
||||||
for retry := 0; retry <= d.partBodyMaxRetries; retry++ {
|
for retry := 0; retry <= d.partBodyMaxRetries; retry++ {
|
||||||
n, err = d.tryDownloadChunk(in, &chunk)
|
n, err = d.tryDownloadChunk(¶ms, &chunk)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -444,9 +375,10 @@ func (d *downloader) downloadChunk(chunk dlchunk) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk.cur = 0
|
chunk.cur = 0
|
||||||
logMessage(d.cfg.S3, aws.LogDebugWithRequestRetries,
|
|
||||||
fmt.Sprintf("DEBUG: object part body download interrupted %s, err, %v, retrying attempt %d",
|
d.cfg.Logger.Logf(logging.Debug,
|
||||||
aws.StringValue(in.Key), err, retry))
|
"object part body download interrupted %s, err, %v, retrying attempt %d",
|
||||||
|
aws.ToString(params.Key), err, retry)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.incrWritten(n)
|
d.incrWritten(n)
|
||||||
|
|
@ -454,14 +386,14 @@ func (d *downloader) downloadChunk(chunk dlchunk) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *downloader) tryDownloadChunk(in *s3.GetObjectInput, w io.Writer) (int64, error) {
|
func (d *downloader) tryDownloadChunk(params *s3.GetObjectInput, w io.Writer) (int64, error) {
|
||||||
cleanup := func() {}
|
cleanup := func() {}
|
||||||
if d.cfg.BufferProvider != nil {
|
if d.cfg.BufferProvider != nil {
|
||||||
w, cleanup = d.cfg.BufferProvider.GetReadFrom(w)
|
w, cleanup = d.cfg.BufferProvider.GetReadFrom(w)
|
||||||
}
|
}
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
resp, err := d.cfg.S3.GetObjectWithContext(d.ctx, in, d.cfg.RequestOptions...)
|
resp, err := d.cfg.S3.GetObject(d.ctx, params, d.cfg.ClientOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -480,21 +412,6 @@ func (d *downloader) tryDownloadChunk(in *s3.GetObjectInput, w io.Writer) (int64
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func logMessage(svc s3iface.S3API, level aws.LogLevelType, msg string) {
|
|
||||||
s, ok := svc.(*s3.S3)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Config.Logger == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Config.LogLevel.Matches(level) {
|
|
||||||
s.Config.Logger.Log(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getTotalBytes is a thread-safe getter for retrieving the total byte status.
|
// getTotalBytes is a thread-safe getter for retrieving the total byte status.
|
||||||
func (d *downloader) getTotalBytes() int64 {
|
func (d *downloader) getTotalBytes() int64 {
|
||||||
d.m.Lock()
|
d.m.Lock()
|
||||||
|
|
@ -519,8 +436,8 @@ func (d *downloader) setTotalBytes(resp *s3.GetObjectOutput) {
|
||||||
if resp.ContentRange == nil {
|
if resp.ContentRange == nil {
|
||||||
// ContentRange is nil when the full file contents is provided, and
|
// ContentRange is nil when the full file contents is provided, and
|
||||||
// is not chunked. Use ContentLength instead.
|
// is not chunked. Use ContentLength instead.
|
||||||
if resp.ContentLength != nil {
|
if resp.ContentLength > 0 {
|
||||||
d.totalBytes = *resp.ContentLength
|
d.totalBytes = resp.ContentLength
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
6
vendor/github.com/aws/aws-sdk-go-v2/feature/s3/manager/go_module_metadata.go
generated
vendored
Normal file
6
vendor/github.com/aws/aws-sdk-go-v2/feature/s3/manager/go_module_metadata.go
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Code generated by internal/repotools/cmd/updatemodulemeta DO NOT EDIT.
|
||||||
|
|
||||||
|
package manager
|
||||||
|
|
||||||
|
// goModuleVersion is the tagged release for this module
|
||||||
|
const goModuleVersion = "1.11.67"
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type byteSlicePool interface {
|
type byteSlicePool interface {
|
||||||
Get(aws.Context) (*[]byte, error)
|
Get(context.Context) (*[]byte, error)
|
||||||
Put(*[]byte)
|
Put(*[]byte)
|
||||||
ModifyCapacity(int)
|
ModifyCapacity(int)
|
||||||
SliceSize() int64
|
SliceSize() int64
|
||||||
|
|
@ -40,7 +39,7 @@ func newMaxSlicePool(sliceSize int64) *maxSlicePool {
|
||||||
|
|
||||||
var errZeroCapacity = fmt.Errorf("get called on zero capacity pool")
|
var errZeroCapacity = fmt.Errorf("get called on zero capacity pool")
|
||||||
|
|
||||||
func (p *maxSlicePool) Get(ctx aws.Context) (*[]byte, error) {
|
func (p *maxSlicePool) Get(ctx context.Context) (*[]byte, error) {
|
||||||
// check if context is canceled before attempting to get a slice
|
// check if context is canceled before attempting to get a slice
|
||||||
// this ensures priority is given to the cancel case first
|
// this ensures priority is given to the cancel case first
|
||||||
select {
|
select {
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -1,27 +1,24 @@
|
||||||
package aws
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/internal/sdkio"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser. Allows the
|
// ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser. Allows the
|
||||||
// SDK to accept an io.Reader that is not also an io.Seeker for unsigned
|
// SDK to accept an io.Reader that is not also an io.Seeker for unsigned
|
||||||
// streaming payload API operations.
|
// streaming payload API operations.
|
||||||
//
|
//
|
||||||
// A ReadSeekCloser wrapping an nonseekable io.Reader used in an API
|
// A readSeekCloser wrapping an nonseekable io.Reader used in an API operation's
|
||||||
// operation's input will prevent that operation being retried in the case of
|
// input will prevent that operation being retried in the case of
|
||||||
// network errors, and cause operation requests to fail if the operation
|
// network errors, and cause operation requests to fail if yhe operation
|
||||||
// requires payload signing.
|
// requires payload signing.
|
||||||
//
|
//
|
||||||
// Note: If using With S3 PutObject to stream an object upload The SDK's S3
|
// Note: If using with S3 PutObject to stream an object upload. The SDK's S3
|
||||||
// Upload manager (s3manager.Uploader) provides support for streaming with the
|
// Upload Manager(s3manager.Uploader) provides support for streaming
|
||||||
// ability to retry network errors.
|
// with the ability to retry network errors.
|
||||||
func ReadSeekCloser(r io.Reader) ReaderSeekerCloser {
|
func ReadSeekCloser(r io.Reader) *ReaderSeekerCloser {
|
||||||
return ReaderSeekerCloser{r}
|
return &ReaderSeekerCloser{r}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReaderSeekerCloser represents a reader that can also delegate io.Seeker and
|
// ReaderSeekerCloser represents a reader that can also delegate io.Seeker and
|
||||||
|
|
@ -30,20 +27,67 @@ type ReaderSeekerCloser struct {
|
||||||
r io.Reader
|
r io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsReaderSeekable returns if the underlying reader type can be seeked. A
|
// seekerLen attempts to get the number of bytes remaining at the seeker's
|
||||||
// io.Reader might not actually be seekable if it is the ReaderSeekerCloser
|
// current position. Returns the number of bytes remaining or error.
|
||||||
// type.
|
func seekerLen(s io.Seeker) (int64, error) {
|
||||||
func IsReaderSeekable(r io.Reader) bool {
|
// Determine if the seeker is actually seekable. ReaderSeekerCloser
|
||||||
switch v := r.(type) {
|
// hides the fact that a io.Readers might not actually be seekable.
|
||||||
case ReaderSeekerCloser:
|
switch v := s.(type) {
|
||||||
return v.IsSeeker()
|
|
||||||
case *ReaderSeekerCloser:
|
case *ReaderSeekerCloser:
|
||||||
return v.IsSeeker()
|
return v.GetLen()
|
||||||
case io.ReadSeeker:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return computeSeekerLength(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLen returns the length of the bytes remaining in the underlying reader.
|
||||||
|
// Checks first for Len(), then io.Seeker to determine the size of the
|
||||||
|
// underlying reader.
|
||||||
|
//
|
||||||
|
// Will return -1 if the length cannot be determined.
|
||||||
|
func (r *ReaderSeekerCloser) GetLen() (int64, error) {
|
||||||
|
if l, ok := r.HasLen(); ok {
|
||||||
|
return int64(l), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if s, ok := r.r.(io.Seeker); ok {
|
||||||
|
return computeSeekerLength(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func computeSeekerLength(s io.Seeker) (int64, error) {
|
||||||
|
curOffset, err := s.Seek(0, io.SeekCurrent)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endOffset, err := s.Seek(0, io.SeekEnd)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.Seek(curOffset, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return endOffset - curOffset, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasLen returns the length of the underlying reader if the value implements
|
||||||
|
// the Len() int method.
|
||||||
|
func (r *ReaderSeekerCloser) HasLen() (int, bool) {
|
||||||
|
type lenner interface {
|
||||||
|
Len() int
|
||||||
|
}
|
||||||
|
|
||||||
|
if lr, ok := r.r.(lenner); ok {
|
||||||
|
return lr.Len(), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read reads from the reader up to size of p. The number of bytes read, and
|
// Read reads from the reader up to size of p. The number of bytes read, and
|
||||||
|
|
@ -53,7 +97,7 @@ func IsReaderSeekable(r io.Reader) bool {
|
||||||
// returned.
|
// returned.
|
||||||
//
|
//
|
||||||
// Performs the same functionality as io.Reader Read
|
// Performs the same functionality as io.Reader Read
|
||||||
func (r ReaderSeekerCloser) Read(p []byte) (int, error) {
|
func (r *ReaderSeekerCloser) Read(p []byte) (int, error) {
|
||||||
switch t := r.r.(type) {
|
switch t := r.r.(type) {
|
||||||
case io.Reader:
|
case io.Reader:
|
||||||
return t.Read(p)
|
return t.Read(p)
|
||||||
|
|
@ -67,7 +111,7 @@ func (r ReaderSeekerCloser) Read(p []byte) (int, error) {
|
||||||
// and an error, if any.
|
// and an error, if any.
|
||||||
//
|
//
|
||||||
// If the ReaderSeekerCloser is not an io.Seeker nothing will be done.
|
// If the ReaderSeekerCloser is not an io.Seeker nothing will be done.
|
||||||
func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) {
|
func (r *ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) {
|
||||||
switch t := r.r.(type) {
|
switch t := r.r.(type) {
|
||||||
case io.Seeker:
|
case io.Seeker:
|
||||||
return t.Seek(offset, whence)
|
return t.Seek(offset, whence)
|
||||||
|
|
@ -76,80 +120,15 @@ func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSeeker returns if the underlying reader is also a seeker.
|
// IsSeeker returns if the underlying reader is also a seeker.
|
||||||
func (r ReaderSeekerCloser) IsSeeker() bool {
|
func (r *ReaderSeekerCloser) IsSeeker() bool {
|
||||||
_, ok := r.r.(io.Seeker)
|
_, ok := r.r.(io.Seeker)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasLen returns the length of the underlying reader if the value implements
|
|
||||||
// the Len() int method.
|
|
||||||
func (r ReaderSeekerCloser) HasLen() (int, bool) {
|
|
||||||
type lenner interface {
|
|
||||||
Len() int
|
|
||||||
}
|
|
||||||
|
|
||||||
if lr, ok := r.r.(lenner); ok {
|
|
||||||
return lr.Len(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLen returns the length of the bytes remaining in the underlying reader.
|
|
||||||
// Checks first for Len(), then io.Seeker to determine the size of the
|
|
||||||
// underlying reader.
|
|
||||||
//
|
|
||||||
// Will return -1 if the length cannot be determined.
|
|
||||||
func (r ReaderSeekerCloser) GetLen() (int64, error) {
|
|
||||||
if l, ok := r.HasLen(); ok {
|
|
||||||
return int64(l), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if s, ok := r.r.(io.Seeker); ok {
|
|
||||||
return seekerLen(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SeekerLen attempts to get the number of bytes remaining at the seeker's
|
|
||||||
// current position. Returns the number of bytes remaining or error.
|
|
||||||
func SeekerLen(s io.Seeker) (int64, error) {
|
|
||||||
// Determine if the seeker is actually seekable. ReaderSeekerCloser
|
|
||||||
// hides the fact that a io.Readers might not actually be seekable.
|
|
||||||
switch v := s.(type) {
|
|
||||||
case ReaderSeekerCloser:
|
|
||||||
return v.GetLen()
|
|
||||||
case *ReaderSeekerCloser:
|
|
||||||
return v.GetLen()
|
|
||||||
}
|
|
||||||
|
|
||||||
return seekerLen(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func seekerLen(s io.Seeker) (int64, error) {
|
|
||||||
curOffset, err := s.Seek(0, sdkio.SeekCurrent)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
endOffset, err := s.Seek(0, sdkio.SeekEnd)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = s.Seek(curOffset, sdkio.SeekStart)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return endOffset - curOffset, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close closes the ReaderSeekerCloser.
|
// Close closes the ReaderSeekerCloser.
|
||||||
//
|
//
|
||||||
// If the ReaderSeekerCloser is not an io.Closer nothing will be done.
|
// If the ReaderSeekerCloser is not an io.Closer nothing will be done.
|
||||||
func (r ReaderSeekerCloser) Close() error {
|
func (r *ReaderSeekerCloser) Close() error {
|
||||||
switch t := r.r.(type) {
|
switch t := r.r.(type) {
|
||||||
case io.Closer:
|
case io.Closer:
|
||||||
return t.Close()
|
return t.Close()
|
||||||
|
|
@ -206,59 +185,3 @@ func (b *WriteAtBuffer) Bytes() []byte {
|
||||||
defer b.m.Unlock()
|
defer b.m.Unlock()
|
||||||
return b.buf
|
return b.buf
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultiCloser is a utility to close multiple io.Closers within a single
|
|
||||||
// statement.
|
|
||||||
type MultiCloser []io.Closer
|
|
||||||
|
|
||||||
// Close closes all of the io.Closers making up the MultiClosers. Any
|
|
||||||
// errors that occur while closing will be returned in the order they
|
|
||||||
// occur.
|
|
||||||
func (m MultiCloser) Close() error {
|
|
||||||
var errs errors
|
|
||||||
for _, c := range m {
|
|
||||||
err := c.Close()
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(errs) != 0 {
|
|
||||||
return errs
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type errors []error
|
|
||||||
|
|
||||||
func (es errors) Error() string {
|
|
||||||
var parts []string
|
|
||||||
for _, e := range es {
|
|
||||||
parts = append(parts, e.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(parts, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopySeekableBody copies the seekable body to an io.Writer
|
|
||||||
func CopySeekableBody(dst io.Writer, src io.ReadSeeker) (int64, error) {
|
|
||||||
curPos, err := src.Seek(0, sdkio.SeekCurrent)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy errors may be assumed to be from the body.
|
|
||||||
n, err := io.Copy(dst, src)
|
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// seek back to the first position after reading to reset
|
|
||||||
// the body for transmission.
|
|
||||||
_, err = src.Seek(curPos, sdkio.SeekStart)
|
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
||||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
"github.com/aws/aws-sdk-go-v2/aws/middleware"
|
||||||
"github.com/aws/aws-sdk-go/aws/client"
|
"github.com/aws/aws-sdk-go-v2/internal/awsutil"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
"github.com/aws/aws-sdk-go/aws/request"
|
"github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||||
"github.com/aws/aws-sdk-go/service/s3"
|
|
||||||
"github.com/aws/aws-sdk-go/service/s3/s3iface"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MaxUploadParts is the maximum allowed number of parts in a multi-part upload
|
// MaxUploadParts is the maximum allowed number of parts in a multi-part upload
|
||||||
// on Amazon S3.
|
// on Amazon S3.
|
||||||
const MaxUploadParts = 10000
|
const MaxUploadParts int32 = 10000
|
||||||
|
|
||||||
// MinUploadPartSize is the minimum allowed part size when uploading a part to
|
// MinUploadPartSize is the minimum allowed part size when uploading a part to
|
||||||
// Amazon S3.
|
// Amazon S3.
|
||||||
|
|
@ -40,58 +40,55 @@ const DefaultUploadConcurrency = 5
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// u := s3manager.NewUploader(opts)
|
// u := manager.NewUploader(client)
|
||||||
// output, err := u.upload(input)
|
// output, err := u.upload(context.Background(), input)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// if multierr, ok := err.(s3manager.MultiUploadFailure); ok {
|
// var multierr manager.MultiUploadFailure
|
||||||
// // Process error and its associated uploadID
|
// if errors.As(err, &multierr) {
|
||||||
// fmt.Println("Error:", multierr.Code(), multierr.Message(), multierr.UploadID())
|
// fmt.Printf("upload failure UploadID=%s, %s\n", multierr.UploadID(), multierr.Error())
|
||||||
// } else {
|
// } else {
|
||||||
// // Process error generically
|
// fmt.Printf("upload failure, %s\n", err.Error())
|
||||||
// fmt.Println("Error:", err.Error())
|
// }
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
type MultiUploadFailure interface {
|
type MultiUploadFailure interface {
|
||||||
awserr.Error
|
error
|
||||||
|
|
||||||
// Returns the upload id for the S3 multipart upload that failed.
|
// UploadID returns the upload id for the S3 multipart upload that failed.
|
||||||
UploadID() string
|
UploadID() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// So that the Error interface type can be included as an anonymous field
|
|
||||||
// in the multiUploadError struct and not conflict with the error.Error() method.
|
|
||||||
type awsError awserr.Error
|
|
||||||
|
|
||||||
// A multiUploadError wraps the upload ID of a failed s3 multipart upload.
|
// A multiUploadError wraps the upload ID of a failed s3 multipart upload.
|
||||||
// Composed of BaseError for code, message, and original error
|
// Composed of BaseError for code, message, and original error
|
||||||
//
|
//
|
||||||
// Should be used for an error that occurred failing a S3 multipart upload,
|
// Should be used for an error that occurred failing a S3 multipart upload,
|
||||||
// and a upload ID is available. If an uploadID is not available a more relevant
|
// and a upload ID is available. If an uploadID is not available a more relevant
|
||||||
type multiUploadError struct {
|
type multiUploadError struct {
|
||||||
awsError
|
err error
|
||||||
|
|
||||||
// ID for multipart upload which failed.
|
// ID for multipart upload which failed.
|
||||||
uploadID string
|
uploadID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error returns the string representation of the error.
|
// batchItemError returns the string representation of the error.
|
||||||
//
|
//
|
||||||
// # See apierr.BaseError ErrorWithExtra for output format
|
// # See apierr.BaseError ErrorWithExtra for output format
|
||||||
//
|
//
|
||||||
// Satisfies the error interface.
|
// Satisfies the error interface.
|
||||||
func (m multiUploadError) Error() string {
|
func (m *multiUploadError) Error() string {
|
||||||
extra := fmt.Sprintf("upload id: %s", m.uploadID)
|
var extra string
|
||||||
return awserr.SprintError(m.Code(), m.Message(), extra, m.OrigErr())
|
if m.err != nil {
|
||||||
|
extra = fmt.Sprintf(", cause: %s", m.err.Error())
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("upload multipart failed, upload id: %s%s", m.uploadID, extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation of the error.
|
// Unwrap returns the underlying error that cause the upload failure
|
||||||
// Alias for Error to satisfy the stringer interface.
|
func (m *multiUploadError) Unwrap() error {
|
||||||
func (m multiUploadError) String() string {
|
return m.err
|
||||||
return m.Error()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadID returns the id of the S3 upload which failed.
|
// UploadID returns the id of the S3 upload which failed.
|
||||||
func (m multiUploadError) UploadID() string {
|
func (m *multiUploadError) UploadID() string {
|
||||||
return m.uploadID
|
return m.uploadID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,23 +97,68 @@ type UploadOutput struct {
|
||||||
// The URL where the object was uploaded to.
|
// The URL where the object was uploaded to.
|
||||||
Location string
|
Location string
|
||||||
|
|
||||||
|
// The ID for a multipart upload to S3. In the case of an error the error
|
||||||
|
// can be cast to the MultiUploadFailure interface to extract the upload ID.
|
||||||
|
// Will be empty string if multipart upload was not used, and the object
|
||||||
|
// was uploaded as a single PutObject call.
|
||||||
|
UploadID string
|
||||||
|
|
||||||
|
// The list of parts that were uploaded and their checksums. Will be empty
|
||||||
|
// if multipart upload was not used, and the object was uploaded as a
|
||||||
|
// single PutObject call.
|
||||||
|
CompletedParts []types.CompletedPart
|
||||||
|
|
||||||
|
// Indicates whether the uploaded object uses an S3 Bucket Key for server-side
|
||||||
|
// encryption with Amazon Web Services KMS (SSE-KMS).
|
||||||
|
BucketKeyEnabled bool
|
||||||
|
|
||||||
|
// The base64-encoded, 32-bit CRC32 checksum of the object.
|
||||||
|
ChecksumCRC32 *string
|
||||||
|
|
||||||
|
// The base64-encoded, 32-bit CRC32C checksum of the object.
|
||||||
|
ChecksumCRC32C *string
|
||||||
|
|
||||||
|
// The base64-encoded, 160-bit SHA-1 digest of the object.
|
||||||
|
ChecksumSHA1 *string
|
||||||
|
|
||||||
|
// The base64-encoded, 256-bit SHA-256 digest of the object.
|
||||||
|
ChecksumSHA256 *string
|
||||||
|
|
||||||
|
// Entity tag for the uploaded object.
|
||||||
|
ETag *string
|
||||||
|
|
||||||
|
// If the object expiration is configured, this will contain the expiration date
|
||||||
|
// (expiry-date) and rule ID (rule-id). The value of rule-id is URL encoded.
|
||||||
|
Expiration *string
|
||||||
|
|
||||||
|
// The object key of the newly created object.
|
||||||
|
Key *string
|
||||||
|
|
||||||
|
// If present, indicates that the requester was successfully charged for the
|
||||||
|
// request.
|
||||||
|
RequestCharged types.RequestCharged
|
||||||
|
|
||||||
|
// If present, specifies the ID of the Amazon Web Services Key Management Service
|
||||||
|
// (Amazon Web Services KMS) symmetric customer managed customer master key (CMK)
|
||||||
|
// that was used for the object.
|
||||||
|
SSEKMSKeyId *string
|
||||||
|
|
||||||
|
// If you specified server-side encryption either with an Amazon S3-managed
|
||||||
|
// encryption key or an Amazon Web Services KMS customer master key (CMK) in your
|
||||||
|
// initiate multipart upload request, the response includes this header. It
|
||||||
|
// confirms the encryption algorithm that Amazon S3 used to encrypt the object.
|
||||||
|
ServerSideEncryption types.ServerSideEncryption
|
||||||
|
|
||||||
// The version of the object that was uploaded. Will only be populated if
|
// The version of the object that was uploaded. Will only be populated if
|
||||||
// the S3 Bucket is versioned. If the bucket is not versioned this field
|
// the S3 Bucket is versioned. If the bucket is not versioned this field
|
||||||
// will not be set.
|
// will not be set.
|
||||||
VersionID *string
|
VersionID *string
|
||||||
|
|
||||||
// The ID for a multipart upload to S3. In the case of an error the error
|
|
||||||
// can be cast to the MultiUploadFailure interface to extract the upload ID.
|
|
||||||
UploadID string
|
|
||||||
|
|
||||||
// Entity tag of the object.
|
|
||||||
ETag *string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithUploaderRequestOptions appends to the Uploader's API request options.
|
// WithUploaderRequestOptions appends to the Uploader's API client options.
|
||||||
func WithUploaderRequestOptions(opts ...request.Option) func(*Uploader) {
|
func WithUploaderRequestOptions(opts ...func(*s3.Options)) func(*Uploader) {
|
||||||
return func(u *Uploader) {
|
return func(u *Uploader) {
|
||||||
u.RequestOptions = append(u.RequestOptions, opts...)
|
u.ClientOptions = append(u.ClientOptions, opts...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,13 +166,34 @@ func WithUploaderRequestOptions(opts ...request.Option) func(*Uploader) {
|
||||||
// on this structure for multiple objects and across concurrent goroutines.
|
// on this structure for multiple objects and across concurrent goroutines.
|
||||||
// Mutating the Uploader's properties is not safe to be done concurrently.
|
// Mutating the Uploader's properties is not safe to be done concurrently.
|
||||||
//
|
//
|
||||||
// The ContentMD5 member for pre-computed MD5 checksums will be ignored for
|
// # Pre-computed Checksums
|
||||||
// multipart uploads. Objects that will be uploaded in a single part, the
|
|
||||||
// ContentMD5 will be used.
|
|
||||||
//
|
//
|
||||||
// The Checksum members for pre-computed checksums will be ignored for
|
// Care must be taken when using pre-computed checksums the transfer upload
|
||||||
// multipart uploads. Objects that will be uploaded in a single part, will
|
// manager. The format and value of the checksum differs based on if the upload
|
||||||
// include the checksum member in the request.
|
// will preformed as a single or multipart upload.
|
||||||
|
//
|
||||||
|
// Uploads that are smaller than the Uploader's PartSize will be uploaded using
|
||||||
|
// the PutObject API operation. Pre-computed checksum of the uploaded object's
|
||||||
|
// content are valid for these single part uploads. If the checksum provided
|
||||||
|
// does not match the uploaded content the upload will fail.
|
||||||
|
//
|
||||||
|
// Uploads that are larger than the Uploader's PartSize will be uploaded using
|
||||||
|
// multi-part upload. The Pre-computed checksums for these uploads are a
|
||||||
|
// checksum of checksums of each part. Not a checksum of the full uploaded
|
||||||
|
// bytes. With the format of "<checksum of checksum>-<numberParts>", (e.g.
|
||||||
|
// "DUoRhQ==-3"). If a pre-computed checksum is provided that does not match
|
||||||
|
// this format, as matches the content uploaded, the upload will fail.
|
||||||
|
//
|
||||||
|
// ContentMD5 for multipart upload is explicitly ignored for multipart upload,
|
||||||
|
// and its value is suppressed.
|
||||||
|
//
|
||||||
|
// # Automatically Computed Checksums
|
||||||
|
//
|
||||||
|
// When the ChecksumAlgorithm member of Upload's input parameter PutObjectInput
|
||||||
|
// is set to a valid value, the SDK will automatically compute the checksum of
|
||||||
|
// the individual uploaded parts. The UploadOutput result from Upload will
|
||||||
|
// include the checksum of part checksums provided by S3
|
||||||
|
// CompleteMultipartUpload API call.
|
||||||
type Uploader struct {
|
type Uploader struct {
|
||||||
// The buffer size (in bytes) to use when buffering data into chunks and
|
// The buffer size (in bytes) to use when buffering data into chunks and
|
||||||
// sending them as parts to S3. The minimum allowed part size is 5MB, and
|
// sending them as parts to S3. The minimum allowed part size is 5MB, and
|
||||||
|
|
@ -164,14 +227,14 @@ type Uploader struct {
|
||||||
// error must be used to signal end of stream.
|
// error must be used to signal end of stream.
|
||||||
//
|
//
|
||||||
// Defaults to package const's MaxUploadParts value.
|
// Defaults to package const's MaxUploadParts value.
|
||||||
MaxUploadParts int
|
MaxUploadParts int32
|
||||||
|
|
||||||
// The client to use when uploading to S3.
|
// The client to use when uploading to S3.
|
||||||
S3 s3iface.S3API
|
S3 UploadAPIClient
|
||||||
|
|
||||||
// List of request options that will be passed down to individual API
|
// List of request options that will be passed down to individual API
|
||||||
// operation requests made by the uploader.
|
// operation requests made by the uploader.
|
||||||
RequestOptions []request.Option
|
ClientOptions []func(*s3.Options)
|
||||||
|
|
||||||
// Defines the buffer strategy used when uploading a part
|
// Defines the buffer strategy used when uploading a part
|
||||||
BufferProvider ReadSeekerWriteToProvider
|
BufferProvider ReadSeekerWriteToProvider
|
||||||
|
|
@ -187,21 +250,23 @@ type Uploader struct {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// // The session the S3 Uploader will use
|
// // Load AWS Config
|
||||||
// sess := session.Must(session.NewSession())
|
// cfg, err := config.LoadDefaultConfig(context.TODO())
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// // Create an uploader with the session and default options
|
// // Create an S3 Client with the config
|
||||||
// uploader := s3manager.NewUploader(sess)
|
// client := s3.NewFromConfig(cfg)
|
||||||
//
|
//
|
||||||
// // Create an uploader with the session and custom options
|
// // Create an uploader passing it the client
|
||||||
// uploader := s3manager.NewUploader(session, func(u *s3manager.Uploader) {
|
// uploader := manager.NewUploader(client)
|
||||||
// u.PartSize = 64 * 1024 * 1024 // 64MB per part
|
//
|
||||||
|
// // Create an uploader with the client and custom options
|
||||||
|
// uploader := manager.NewUploader(client, func(u *manager.Uploader) {
|
||||||
|
// u.PartSize = 64 * 1024 * 1024 // 64MB per part
|
||||||
// })
|
// })
|
||||||
func NewUploader(c client.ConfigProvider, options ...func(*Uploader)) *Uploader {
|
func NewUploader(client UploadAPIClient, options ...func(*Uploader)) *Uploader {
|
||||||
return newUploader(s3.New(c), options...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newUploader(client s3iface.S3API, options ...func(*Uploader)) *Uploader {
|
|
||||||
u := &Uploader{
|
u := &Uploader{
|
||||||
S3: client,
|
S3: client,
|
||||||
PartSize: DefaultUploadPartSize,
|
PartSize: DefaultUploadPartSize,
|
||||||
|
|
@ -220,72 +285,10 @@ func newUploader(client s3iface.S3API, options ...func(*Uploader)) *Uploader {
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUploaderWithClient creates a new Uploader instance to upload objects to S3. Pass in
|
// Upload uploads an object to S3, intelligently buffering large
|
||||||
// additional functional options to customize the uploader's behavior. Requires
|
|
||||||
// a S3 service client to make S3 API calls.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// // The session the S3 Uploader will use
|
|
||||||
// sess := session.Must(session.NewSession())
|
|
||||||
//
|
|
||||||
// // S3 service client the Upload manager will use.
|
|
||||||
// s3Svc := s3.New(sess)
|
|
||||||
//
|
|
||||||
// // Create an uploader with S3 client and default options
|
|
||||||
// uploader := s3manager.NewUploaderWithClient(s3Svc)
|
|
||||||
//
|
|
||||||
// // Create an uploader with S3 client and custom options
|
|
||||||
// uploader := s3manager.NewUploaderWithClient(s3Svc, func(u *s3manager.Uploader) {
|
|
||||||
// u.PartSize = 64 * 1024 * 1024 // 64MB per part
|
|
||||||
// })
|
|
||||||
func NewUploaderWithClient(svc s3iface.S3API, options ...func(*Uploader)) *Uploader {
|
|
||||||
return newUploader(svc, options...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload uploads an object to S3, intelligently buffering large files into
|
|
||||||
// smaller chunks and sending them in parallel across multiple goroutines. You
|
|
||||||
// can configure the buffer size and concurrency through the Uploader's parameters.
|
|
||||||
//
|
|
||||||
// Additional functional options can be provided to configure the individual
|
|
||||||
// upload. These options are copies of the Uploader instance Upload is called from.
|
|
||||||
// Modifying the options will not impact the original Uploader instance.
|
|
||||||
//
|
|
||||||
// Use the WithUploaderRequestOptions helper function to pass in request
|
|
||||||
// options that will be applied to all API operations made with this uploader.
|
|
||||||
//
|
|
||||||
// It is safe to call this method concurrently across goroutines.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// // Upload input parameters
|
|
||||||
// upParams := &s3manager.UploadInput{
|
|
||||||
// Bucket: &bucketName,
|
|
||||||
// Key: &keyName,
|
|
||||||
// Body: file,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Perform an upload.
|
|
||||||
// result, err := uploader.Upload(upParams)
|
|
||||||
//
|
|
||||||
// // Perform upload with options different than the those in the Uploader.
|
|
||||||
// result, err := uploader.Upload(upParams, func(u *s3manager.Uploader) {
|
|
||||||
// u.PartSize = 10 * 1024 * 1024 // 10MB part size
|
|
||||||
// u.LeavePartsOnError = true // Don't delete the parts if the upload fails.
|
|
||||||
// })
|
|
||||||
func (u Uploader) Upload(input *UploadInput, options ...func(*Uploader)) (*UploadOutput, error) {
|
|
||||||
return u.UploadWithContext(aws.BackgroundContext(), input, options...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadWithContext uploads an object to S3, intelligently buffering large
|
|
||||||
// files into smaller chunks and sending them in parallel across multiple
|
// files into smaller chunks and sending them in parallel across multiple
|
||||||
// goroutines. You can configure the buffer size and concurrency through the
|
// goroutines. You can configure the buffer size and concurrency through the
|
||||||
// Uploader's parameters.
|
// Uploader parameters.
|
||||||
//
|
|
||||||
// UploadWithContext is the same as Upload with the additional support for
|
|
||||||
// Context input parameters. The Context must not be nil. A nil Context will
|
|
||||||
// cause a panic. Use the context to add deadlining, timeouts, etc. The
|
|
||||||
// UploadWithContext may create sub-contexts for individual underlying requests.
|
|
||||||
//
|
//
|
||||||
// Additional functional options can be provided to configure the individual
|
// Additional functional options can be provided to configure the individual
|
||||||
// upload. These options are copies of the Uploader instance Upload is called from.
|
// upload. These options are copies of the Uploader instance Upload is called from.
|
||||||
|
|
@ -295,80 +298,34 @@ func (u Uploader) Upload(input *UploadInput, options ...func(*Uploader)) (*Uploa
|
||||||
// options that will be applied to all API operations made with this uploader.
|
// options that will be applied to all API operations made with this uploader.
|
||||||
//
|
//
|
||||||
// It is safe to call this method concurrently across goroutines.
|
// It is safe to call this method concurrently across goroutines.
|
||||||
func (u Uploader) UploadWithContext(ctx aws.Context, input *UploadInput, opts ...func(*Uploader)) (*UploadOutput, error) {
|
func (u Uploader) Upload(ctx context.Context, input *s3.PutObjectInput, opts ...func(*Uploader)) (
|
||||||
|
*UploadOutput, error,
|
||||||
|
) {
|
||||||
i := uploader{in: input, cfg: u, ctx: ctx}
|
i := uploader{in: input, cfg: u, ctx: ctx}
|
||||||
|
|
||||||
|
// Copy ClientOptions
|
||||||
|
clientOptions := make([]func(*s3.Options), 0, len(i.cfg.ClientOptions)+1)
|
||||||
|
clientOptions = append(clientOptions, func(o *s3.Options) {
|
||||||
|
o.APIOptions = append(o.APIOptions,
|
||||||
|
middleware.AddSDKAgentKey(middleware.FeatureMetadata, userAgentKey),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
clientOptions = append(clientOptions, i.cfg.ClientOptions...)
|
||||||
|
i.cfg.ClientOptions = clientOptions
|
||||||
|
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(&i.cfg)
|
opt(&i.cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
i.cfg.RequestOptions = append(i.cfg.RequestOptions, request.WithAppendUserAgent("S3Manager"))
|
|
||||||
|
|
||||||
return i.upload()
|
return i.upload()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadWithIterator will upload a batched amount of objects to S3. This operation uses
|
|
||||||
// the iterator pattern to know which object to upload next. Since this is an interface this
|
|
||||||
// allows for custom defined functionality.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// svc:= s3manager.NewUploader(sess)
|
|
||||||
//
|
|
||||||
// objects := []BatchUploadObject{
|
|
||||||
// {
|
|
||||||
// Object: &s3manager.UploadInput {
|
|
||||||
// Key: aws.String("key"),
|
|
||||||
// Bucket: aws.String("bucket"),
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// iter := &s3manager.UploadObjectsIterator{Objects: objects}
|
|
||||||
// if err := svc.UploadWithIterator(aws.BackgroundContext(), iter); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
func (u Uploader) UploadWithIterator(ctx aws.Context, iter BatchUploadIterator, opts ...func(*Uploader)) error {
|
|
||||||
var errs []Error
|
|
||||||
for iter.Next() {
|
|
||||||
object := iter.UploadObject()
|
|
||||||
if _, err := u.UploadWithContext(ctx, object.Object, opts...); err != nil {
|
|
||||||
s3Err := Error{
|
|
||||||
OrigErr: err,
|
|
||||||
Bucket: object.Object.Bucket,
|
|
||||||
Key: object.Object.Key,
|
|
||||||
}
|
|
||||||
|
|
||||||
errs = append(errs, s3Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if object.After == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := object.After(); err != nil {
|
|
||||||
s3Err := Error{
|
|
||||||
OrigErr: err,
|
|
||||||
Bucket: object.Object.Bucket,
|
|
||||||
Key: object.Object.Key,
|
|
||||||
}
|
|
||||||
|
|
||||||
errs = append(errs, s3Err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return NewBatchError("BatchedUploadIncomplete", "some objects have failed to upload.", errs)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// internal structure to manage an upload to S3.
|
// internal structure to manage an upload to S3.
|
||||||
type uploader struct {
|
type uploader struct {
|
||||||
ctx aws.Context
|
ctx context.Context
|
||||||
cfg Uploader
|
cfg Uploader
|
||||||
|
|
||||||
in *UploadInput
|
in *s3.PutObjectInput
|
||||||
|
|
||||||
readerPos int64 // current reader position
|
readerPos int64 // current reader position
|
||||||
totalSize int64 // set to -1 if the size is not known
|
totalSize int64 // set to -1 if the size is not known
|
||||||
|
|
@ -378,13 +335,12 @@ type uploader struct {
|
||||||
// multipart upload.
|
// multipart upload.
|
||||||
func (u *uploader) upload() (*UploadOutput, error) {
|
func (u *uploader) upload() (*UploadOutput, error) {
|
||||||
if err := u.init(); err != nil {
|
if err := u.init(); err != nil {
|
||||||
return nil, awserr.New("ReadRequestBody", "unable to initialize upload", err)
|
return nil, fmt.Errorf("unable to initialize upload: %w", err)
|
||||||
}
|
}
|
||||||
defer u.cfg.partPool.Close()
|
defer u.cfg.partPool.Close()
|
||||||
|
|
||||||
if u.cfg.PartSize < MinUploadPartSize {
|
if u.cfg.PartSize < MinUploadPartSize {
|
||||||
msg := fmt.Sprintf("part size must be at least %d bytes", MinUploadPartSize)
|
return nil, fmt.Errorf("part size must be at least %d bytes", MinUploadPartSize)
|
||||||
return nil, awserr.New("ConfigError", msg, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do one read to determine if we have more than one part
|
// Do one read to determine if we have more than one part
|
||||||
|
|
@ -393,7 +349,7 @@ func (u *uploader) upload() (*UploadOutput, error) {
|
||||||
return u.singlePart(reader, cleanup)
|
return u.singlePart(reader, cleanup)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
cleanup()
|
cleanup()
|
||||||
return nil, awserr.New("ReadRequestBody", "read upload data failed", err)
|
return nil, fmt.Errorf("read upload data failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mu := multiuploader{uploader: u}
|
mu := multiuploader{uploader: u}
|
||||||
|
|
@ -402,7 +358,7 @@ func (u *uploader) upload() (*UploadOutput, error) {
|
||||||
|
|
||||||
// init will initialize all default options.
|
// init will initialize all default options.
|
||||||
func (u *uploader) init() error {
|
func (u *uploader) init() error {
|
||||||
if err := validateSupportedARNType(aws.StringValue(u.in.Bucket)); err != nil {
|
if err := validateSupportedARNType(aws.ToString(u.in.Bucket)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -442,7 +398,7 @@ func (u *uploader) initSize() error {
|
||||||
|
|
||||||
switch r := u.in.Body.(type) {
|
switch r := u.in.Body.(type) {
|
||||||
case io.Seeker:
|
case io.Seeker:
|
||||||
n, err := aws.SeekerLen(r)
|
n, err := seekerLen(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -528,27 +484,69 @@ func readFillBuf(r io.Reader, b []byte) (offset int, err error) {
|
||||||
func (u *uploader) singlePart(r io.ReadSeeker, cleanup func()) (*UploadOutput, error) {
|
func (u *uploader) singlePart(r io.ReadSeeker, cleanup func()) (*UploadOutput, error) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
params := &s3.PutObjectInput{}
|
var params s3.PutObjectInput
|
||||||
awsutil.Copy(params, u.in)
|
awsutil.Copy(¶ms, u.in)
|
||||||
params.Body = r
|
params.Body = r
|
||||||
|
|
||||||
// Need to use request form because URL generated in request is
|
// Need to use request form because URL generated in request is
|
||||||
// used in return.
|
// used in return.
|
||||||
req, out := u.cfg.S3.PutObjectRequest(params)
|
|
||||||
req.SetContext(u.ctx)
|
var locationRecorder recordLocationClient
|
||||||
req.ApplyOptions(u.cfg.RequestOptions...)
|
out, err := u.cfg.S3.PutObject(u.ctx, ¶ms,
|
||||||
if err := req.Send(); err != nil {
|
append(u.cfg.ClientOptions, locationRecorder.WrapClient())...)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
url := req.HTTPRequest.URL.String()
|
|
||||||
return &UploadOutput{
|
return &UploadOutput{
|
||||||
Location: url,
|
Location: locationRecorder.location,
|
||||||
VersionID: out.VersionId,
|
|
||||||
ETag: out.ETag,
|
BucketKeyEnabled: out.BucketKeyEnabled,
|
||||||
|
ChecksumCRC32: out.ChecksumCRC32,
|
||||||
|
ChecksumCRC32C: out.ChecksumCRC32C,
|
||||||
|
ChecksumSHA1: out.ChecksumSHA1,
|
||||||
|
ChecksumSHA256: out.ChecksumSHA256,
|
||||||
|
ETag: out.ETag,
|
||||||
|
Expiration: out.Expiration,
|
||||||
|
Key: params.Key,
|
||||||
|
RequestCharged: out.RequestCharged,
|
||||||
|
SSEKMSKeyId: out.SSEKMSKeyId,
|
||||||
|
ServerSideEncryption: out.ServerSideEncryption,
|
||||||
|
VersionID: out.VersionId,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type httpClient interface {
|
||||||
|
Do(r *http.Request) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type recordLocationClient struct {
|
||||||
|
httpClient
|
||||||
|
location string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *recordLocationClient) WrapClient() func(o *s3.Options) {
|
||||||
|
return func(o *s3.Options) {
|
||||||
|
c.httpClient = o.HTTPClient
|
||||||
|
o.HTTPClient = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *recordLocationClient) Do(r *http.Request) (resp *http.Response, err error) {
|
||||||
|
resp, err = c.httpClient.Do(r)
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Request != nil && resp.Request.URL != nil {
|
||||||
|
url := *resp.Request.URL
|
||||||
|
url.RawQuery = ""
|
||||||
|
c.location = url.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
// internal structure to manage a specific multipart upload to S3.
|
// internal structure to manage a specific multipart upload to S3.
|
||||||
type multiuploader struct {
|
type multiuploader struct {
|
||||||
*uploader
|
*uploader
|
||||||
|
|
@ -562,26 +560,28 @@ type multiuploader struct {
|
||||||
// keeps track of a single chunk of data being sent to S3.
|
// keeps track of a single chunk of data being sent to S3.
|
||||||
type chunk struct {
|
type chunk struct {
|
||||||
buf io.ReadSeeker
|
buf io.ReadSeeker
|
||||||
num int64
|
num int32
|
||||||
cleanup func()
|
cleanup func()
|
||||||
}
|
}
|
||||||
|
|
||||||
// completedParts is a wrapper to make parts sortable by their part number,
|
// completedParts is a wrapper to make parts sortable by their part number,
|
||||||
// since S3 required this list to be sent in sorted order.
|
// since S3 required this list to be sent in sorted order.
|
||||||
type completedParts []*s3.CompletedPart
|
type completedParts []types.CompletedPart
|
||||||
|
|
||||||
func (a completedParts) Len() int { return len(a) }
|
func (a completedParts) Len() int { return len(a) }
|
||||||
func (a completedParts) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
func (a completedParts) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
func (a completedParts) Less(i, j int) bool { return *a[i].PartNumber < *a[j].PartNumber }
|
func (a completedParts) Less(i, j int) bool { return a[i].PartNumber < a[j].PartNumber }
|
||||||
|
|
||||||
// upload will perform a multipart upload using the firstBuf buffer containing
|
// upload will perform a multipart upload using the firstBuf buffer containing
|
||||||
// the first chunk of data.
|
// the first chunk of data.
|
||||||
func (u *multiuploader) upload(firstBuf io.ReadSeeker, cleanup func()) (*UploadOutput, error) {
|
func (u *multiuploader) upload(firstBuf io.ReadSeeker, cleanup func()) (*UploadOutput, error) {
|
||||||
params := &s3.CreateMultipartUploadInput{}
|
var params s3.CreateMultipartUploadInput
|
||||||
awsutil.Copy(params, u.in)
|
awsutil.Copy(¶ms, u.in)
|
||||||
|
|
||||||
// Create the multipart
|
// Create the multipart
|
||||||
resp, err := u.cfg.S3.CreateMultipartUploadWithContext(u.ctx, params, u.cfg.RequestOptions...)
|
var locationRecorder recordLocationClient
|
||||||
|
resp, err := u.cfg.S3.CreateMultipartUpload(u.ctx, ¶ms,
|
||||||
|
append(u.cfg.ClientOptions, locationRecorder.WrapClient())...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanup()
|
cleanup()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -596,7 +596,7 @@ func (u *multiuploader) upload(firstBuf io.ReadSeeker, cleanup func()) (*UploadO
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send part 1 to the workers
|
// Send part 1 to the workers
|
||||||
var num int64 = 1
|
var num int32 = 1
|
||||||
ch <- chunk{buf: firstBuf, num: num, cleanup: cleanup}
|
ch <- chunk{buf: firstBuf, num: num, cleanup: cleanup}
|
||||||
|
|
||||||
// Read and queue the rest of the parts
|
// Read and queue the rest of the parts
|
||||||
|
|
@ -625,39 +625,38 @@ func (u *multiuploader) upload(firstBuf io.ReadSeeker, cleanup func()) (*UploadO
|
||||||
// Close the channel, wait for workers, and complete upload
|
// Close the channel, wait for workers, and complete upload
|
||||||
close(ch)
|
close(ch)
|
||||||
u.wg.Wait()
|
u.wg.Wait()
|
||||||
complete := u.complete()
|
completeOut := u.complete()
|
||||||
|
|
||||||
if err := u.geterr(); err != nil {
|
if err := u.geterr(); err != nil {
|
||||||
return nil, &multiUploadError{
|
return nil, &multiUploadError{
|
||||||
awsError: awserr.New(
|
err: err,
|
||||||
"MultipartUpload",
|
|
||||||
"upload multipart failed",
|
|
||||||
err),
|
|
||||||
uploadID: u.uploadID,
|
uploadID: u.uploadID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a presigned URL of the S3 Get Object in order to have parity with
|
|
||||||
// single part upload.
|
|
||||||
getReq, _ := u.cfg.S3.GetObjectRequest(&s3.GetObjectInput{
|
|
||||||
Bucket: u.in.Bucket,
|
|
||||||
Key: u.in.Key,
|
|
||||||
})
|
|
||||||
getReq.Config.Credentials = credentials.AnonymousCredentials
|
|
||||||
getReq.SetContext(u.ctx)
|
|
||||||
uploadLocation, _, _ := getReq.PresignRequest(1)
|
|
||||||
|
|
||||||
return &UploadOutput{
|
return &UploadOutput{
|
||||||
Location: uploadLocation,
|
Location: locationRecorder.location,
|
||||||
VersionID: complete.VersionId,
|
UploadID: u.uploadID,
|
||||||
UploadID: u.uploadID,
|
CompletedParts: u.parts,
|
||||||
ETag: complete.ETag,
|
|
||||||
|
BucketKeyEnabled: completeOut.BucketKeyEnabled,
|
||||||
|
ChecksumCRC32: completeOut.ChecksumCRC32,
|
||||||
|
ChecksumCRC32C: completeOut.ChecksumCRC32C,
|
||||||
|
ChecksumSHA1: completeOut.ChecksumSHA1,
|
||||||
|
ChecksumSHA256: completeOut.ChecksumSHA256,
|
||||||
|
ETag: completeOut.ETag,
|
||||||
|
Expiration: completeOut.Expiration,
|
||||||
|
Key: completeOut.Key,
|
||||||
|
RequestCharged: completeOut.RequestCharged,
|
||||||
|
SSEKMSKeyId: completeOut.SSEKMSKeyId,
|
||||||
|
ServerSideEncryption: completeOut.ServerSideEncryption,
|
||||||
|
VersionID: completeOut.VersionId,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *multiuploader) shouldContinue(part int64, nextChunkLen int, err error) (bool, error) {
|
func (u *multiuploader) shouldContinue(part int32, nextChunkLen int, err error) (bool, error) {
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
return false, awserr.New("ReadRequestBody", "read multipart upload data failed", err)
|
return false, fmt.Errorf("read multipart upload data failed, %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if nextChunkLen == 0 {
|
if nextChunkLen == 0 {
|
||||||
|
|
@ -669,16 +668,16 @@ func (u *multiuploader) shouldContinue(part int64, nextChunkLen int, err error)
|
||||||
|
|
||||||
part++
|
part++
|
||||||
// This upload exceeded maximum number of supported parts, error now.
|
// This upload exceeded maximum number of supported parts, error now.
|
||||||
if part > int64(u.cfg.MaxUploadParts) || part > int64(MaxUploadParts) {
|
if part > u.cfg.MaxUploadParts || part > MaxUploadParts {
|
||||||
var msg string
|
var msg string
|
||||||
if part > int64(u.cfg.MaxUploadParts) {
|
if part > u.cfg.MaxUploadParts {
|
||||||
msg = fmt.Sprintf("exceeded total allowed configured MaxUploadParts (%d). Adjust PartSize to fit in this limit",
|
msg = fmt.Sprintf("exceeded total allowed configured MaxUploadParts (%d). Adjust PartSize to fit in this limit",
|
||||||
u.cfg.MaxUploadParts)
|
u.cfg.MaxUploadParts)
|
||||||
} else {
|
} else {
|
||||||
msg = fmt.Sprintf("exceeded total allowed S3 limit MaxUploadParts (%d). Adjust PartSize to fit in this limit",
|
msg = fmt.Sprintf("exceeded total allowed S3 limit MaxUploadParts (%d). Adjust PartSize to fit in this limit",
|
||||||
MaxUploadParts)
|
MaxUploadParts)
|
||||||
}
|
}
|
||||||
return false, awserr.New("TotalPartsExceeded", msg, nil)
|
return false, fmt.Errorf(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, err
|
return true, err
|
||||||
|
|
@ -712,19 +711,30 @@ func (u *multiuploader) send(c chunk) error {
|
||||||
Bucket: u.in.Bucket,
|
Bucket: u.in.Bucket,
|
||||||
Key: u.in.Key,
|
Key: u.in.Key,
|
||||||
Body: c.buf,
|
Body: c.buf,
|
||||||
UploadId: &u.uploadID,
|
|
||||||
SSECustomerAlgorithm: u.in.SSECustomerAlgorithm,
|
SSECustomerAlgorithm: u.in.SSECustomerAlgorithm,
|
||||||
SSECustomerKey: u.in.SSECustomerKey,
|
SSECustomerKey: u.in.SSECustomerKey,
|
||||||
PartNumber: &c.num,
|
SSECustomerKeyMD5: u.in.SSECustomerKeyMD5,
|
||||||
}
|
ExpectedBucketOwner: u.in.ExpectedBucketOwner,
|
||||||
|
RequestPayer: u.in.RequestPayer,
|
||||||
|
|
||||||
resp, err := u.cfg.S3.UploadPartWithContext(u.ctx, params, u.cfg.RequestOptions...)
|
ChecksumAlgorithm: u.in.ChecksumAlgorithm,
|
||||||
|
// Invalid to set any of the individual ChecksumXXX members from
|
||||||
|
// PutObject as they are never valid for individual parts of a
|
||||||
|
// multipart upload.
|
||||||
|
|
||||||
|
PartNumber: c.num,
|
||||||
|
UploadId: &u.uploadID,
|
||||||
|
}
|
||||||
|
// TODO should do copy then clear?
|
||||||
|
|
||||||
|
resp, err := u.cfg.S3.UploadPart(u.ctx, params, u.cfg.ClientOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
n := c.num
|
var completed types.CompletedPart
|
||||||
completed := &s3.CompletedPart{ETag: resp.ETag, PartNumber: &n}
|
awsutil.Copy(&completed, resp)
|
||||||
|
completed.PartNumber = c.num
|
||||||
|
|
||||||
u.m.Lock()
|
u.m.Lock()
|
||||||
u.parts = append(u.parts, completed)
|
u.parts = append(u.parts, completed)
|
||||||
|
|
@ -760,9 +770,11 @@ func (u *multiuploader) fail() {
|
||||||
Key: u.in.Key,
|
Key: u.in.Key,
|
||||||
UploadId: &u.uploadID,
|
UploadId: &u.uploadID,
|
||||||
}
|
}
|
||||||
_, err := u.cfg.S3.AbortMultipartUploadWithContext(u.ctx, params, u.cfg.RequestOptions...)
|
_, err := u.cfg.S3.AbortMultipartUpload(u.ctx, params, u.cfg.ClientOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logMessage(u.cfg.S3, aws.LogDebug, fmt.Sprintf("failed to abort multipart upload, %v", err))
|
// TODO: Add logging
|
||||||
|
//logMessage(u.cfg.S3, aws.LogDebug, fmt.Sprintf("failed to abort multipart upload, %v", err))
|
||||||
|
_ = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -776,13 +788,12 @@ func (u *multiuploader) complete() *s3.CompleteMultipartUploadOutput {
|
||||||
// Parts must be sorted in PartNumber order.
|
// Parts must be sorted in PartNumber order.
|
||||||
sort.Sort(u.parts)
|
sort.Sort(u.parts)
|
||||||
|
|
||||||
params := &s3.CompleteMultipartUploadInput{
|
var params s3.CompleteMultipartUploadInput
|
||||||
Bucket: u.in.Bucket,
|
awsutil.Copy(¶ms, u.in)
|
||||||
Key: u.in.Key,
|
params.UploadId = &u.uploadID
|
||||||
UploadId: &u.uploadID,
|
params.MultipartUpload = &types.CompletedMultipartUpload{Parts: u.parts}
|
||||||
MultipartUpload: &s3.CompletedMultipartUpload{Parts: u.parts},
|
|
||||||
}
|
resp, err := u.cfg.S3.CompleteMultipartUpload(u.ctx, ¶ms, u.cfg.ClientOptions...)
|
||||||
resp, err := u.cfg.S3.CompleteMultipartUploadWithContext(u.ctx, params, u.cfg.RequestOptions...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
u.seterr(err)
|
u.seterr(err)
|
||||||
u.fail()
|
u.fail()
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
package s3manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/internal/sdkio"
|
"github.com/aws/aws-sdk-go-v2/internal/sdkio"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriterReadFrom defines an interface implementing io.Writer and io.ReaderFrom
|
// WriterReadFrom defines an interface implementing io.Writer and io.ReaderFrom
|
||||||
|
|
@ -51,7 +51,11 @@ func rcopy(dst, src reflect.Value, root bool) {
|
||||||
e := src.Type().Elem()
|
e := src.Type().Elem()
|
||||||
if dst.CanSet() && !src.IsNil() {
|
if dst.CanSet() && !src.IsNil() {
|
||||||
if _, ok := src.Interface().(*time.Time); !ok {
|
if _, ok := src.Interface().(*time.Time); !ok {
|
||||||
dst.Set(reflect.New(e))
|
if dst.Kind() == reflect.String {
|
||||||
|
dst.SetString(e.String())
|
||||||
|
} else {
|
||||||
|
dst.Set(reflect.New(e))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tempValue := reflect.New(e)
|
tempValue := reflect.New(e)
|
||||||
tempValue.Elem().Set(src.Elem())
|
tempValue.Elem().Set(src.Elem())
|
||||||
|
|
@ -59,7 +63,7 @@ func rcopy(dst, src reflect.Value, root bool) {
|
||||||
dst.Set(tempValue)
|
dst.Set(tempValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if src.Elem().IsValid() {
|
if dst.Kind() != reflect.String && src.Elem().IsValid() {
|
||||||
// Keep the current root state since the depth hasn't changed
|
// Keep the current root state since the depth hasn't changed
|
||||||
rcopy(dst.Elem(), src.Elem(), root)
|
rcopy(dst.Elem(), src.Elem(), root)
|
||||||
}
|
}
|
||||||
|
|
@ -15,7 +15,7 @@ func DeepEqual(a, b interface{}) bool {
|
||||||
rb := reflect.Indirect(reflect.ValueOf(b))
|
rb := reflect.Indirect(reflect.ValueOf(b))
|
||||||
|
|
||||||
if raValid, rbValid := ra.IsValid(), rb.IsValid(); !raValid && !rbValid {
|
if raValid, rbValid := ra.IsValid(), rb.IsValid(); !raValid && !rbValid {
|
||||||
// If the elements are both nil, and of the same type they are equal
|
// If the elements are both nil, and of the same type the are equal
|
||||||
// If they are of different types they are not equal
|
// If they are of different types they are not equal
|
||||||
return reflect.TypeOf(a) == reflect.TypeOf(b)
|
return reflect.TypeOf(a) == reflect.TypeOf(b)
|
||||||
} else if raValid != rbValid {
|
} else if raValid != rbValid {
|
||||||
|
|
@ -23,5 +23,11 @@ func DeepEqual(a, b interface{}) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special casing for strings as typed enumerations are string aliases
|
||||||
|
// but are not deep equal.
|
||||||
|
if ra.Kind() == reflect.String && rb.Kind() == reflect.String {
|
||||||
|
return ra.String() == rb.String()
|
||||||
|
}
|
||||||
|
|
||||||
return reflect.DeepEqual(ra.Interface(), rb.Interface())
|
return reflect.DeepEqual(ra.Interface(), rb.Interface())
|
||||||
}
|
}
|
||||||
|
|
@ -185,12 +185,13 @@ func ValuesAtPath(i interface{}, path string) ([]interface{}, error) {
|
||||||
// SetValueAtPath sets a value at the case insensitive lexical path inside
|
// SetValueAtPath sets a value at the case insensitive lexical path inside
|
||||||
// of a structure.
|
// of a structure.
|
||||||
func SetValueAtPath(i interface{}, path string, v interface{}) {
|
func SetValueAtPath(i interface{}, path string, v interface{}) {
|
||||||
rvals := rValuesAtPath(i, path, true, false, v == nil)
|
if rvals := rValuesAtPath(i, path, true, false, v == nil); rvals != nil {
|
||||||
for _, rval := range rvals {
|
for _, rval := range rvals {
|
||||||
if rval.Kind() == reflect.Ptr && rval.IsNil() {
|
if rval.Kind() == reflect.Ptr && rval.IsNil() {
|
||||||
continue
|
continue
|
||||||
|
}
|
||||||
|
setValue(rval, v)
|
||||||
}
|
}
|
||||||
setValue(rval, v)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,7 +216,10 @@ func setValue(dstVal reflect.Value, src interface{}) {
|
||||||
}
|
}
|
||||||
dstVal.Set(srcVal)
|
dstVal.Set(srcVal)
|
||||||
} else {
|
} else {
|
||||||
dstVal.Set(srcVal)
|
if dstVal.Kind() == reflect.String {
|
||||||
|
dstVal.SetString(srcVal.String())
|
||||||
|
} else {
|
||||||
|
dstVal.Set(srcVal)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue