packages feed

amazonka 1.4.5 → 2.0

raw patch · 35 files changed

Files

CHANGELOG.md view
@@ -1,7 +1,613 @@ # Change Log +## [2.0.0](https://github.com/brendanhay/amazonka/tree/2.0.0)+Released: **28 July 2023**, Compare: [2.0.0-rc2](https://github.com/brendanhay/amazonka/compare/2.0.0-rc2...2.0.0)++### Changed++- `amazonka`: Update two missing EC2 metadata keys from [instance metadata categories](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html)+[\#935](https://github.com/brendanhay/amazonka/pull/935)+- `amazonka`: Stop re-exporting a subset of EC2 metadata keys from the root `Amazonka` module.+[\#940](https://github.com/brendanhay/amazonka/pull/940)+  - Metadata users should import `Amazonka.EC2.Metadata` directly.+  - The functions `Amazonka.dynamic`, `Amazonka.metadata` and `Amazonka.userdata` have been removed in favour of their equivalents in `Amazonka.EC2.Metadata` which only require a HTTP `Manager`, not an entire `Env`.+  - It is easy to share a single `Manager` between metadata requests and an Amazonka `Env`:+    - If you create the `Env` first, you can read its `manager :: Manager` field.+    - If you make metadata requests before calling `newEnv`, you must create a `Manager` youself. You can pass this `Manager` to `newEnvFromManager`.++### Fixed++- `aeson ^>= 2.2` is now supported.+[\#938](https://github.com/brendanhay/amazonka/pull/938)++## [2.0.0 RC2](https://github.com/brendanhay/amazonka/tree/2.0.0-rc2)+Released: **10th July, 2023**, Compare: [2.0.0-rc1](https://github.com/brendanhay/amazonka/compare/2.0.0-rc1...2.0.0-rc2)++### Major Changes++- A system of "hooks" was added in PR [\#875](https://github.com/brendanhay/amazonka/pull/875), allowing library clients to inject custom behavior at key points in the request/response cycle. Logging has been reimplemented in terms of these hooks, but they open up a lot of other customization options. Some examples of things that should now be possible:++  - Injecting a [Trace ID for AWS X-Ray](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader) into each request before it is signed and sent,+  - Selectively silencing logging for expected error messages, such as DynamoDB's `ConditionalCheckFailedException`, and+  - Logging all requests Amazonka makes to a separate log, enabling audit of which IAM actions an program actually needs.++  The hooks API is currently experimental, and may change in a later version. Full details and examples are in the `Amazonka.Env.Hooks` module.++- The authentication code in `amazonka` got a full rewrite in PR [\#746](https://github.com/brendanhay/amazonka/pull/746).++  - On Windows, the {credential,config} files are read from `%USERPROFILE%\.aws\{credentials,config}` to [match the AWS SDK](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/creds-file.html#creds-file-general-info).+  - `newEnv` now takes a function of type `EnvNoAuth -> m Env`, which is to fetch credentials in an appropriate manner+  - The `Credentials` type has been removed, you should instead use the following functions corresponding to the departed constructor. All are exported by `Amazonka.Auth`:++    | Old Name          | New Name                     | Args/Comment                                                                                                                                                                                                                                            |+    |-------------------|------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|+    | `FromKeys`        | `fromKeys`                   | `AccessKey`, `SecretKey`.                                                                                                                                                                                                                               |+    | `FromSession`     | `fromSession`                | `AccessKey`, `SecretKey`, `SessionToken`.                                                                                                                                                                                                               |+    |                   | `fromTemporarySession`       | `AccessKey`, `SecretKey`, `SessionToken`, `UTCTime` (expiry time). Likely not useful.                                                                                                                                                                   |+    |                   | `fromKeysEnv`                | None - reads `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and optionally `AWS_SESSION_TOKEN`.                                                                                                                                                          |+    | `FromEnv`         |                              | Removed - look up named environment variables for access key id/secret access key/session token/expiry time.                                                                                                                                            |+    | `FromProfile`     | `fromNamedInstanceProfile`   | `Text` - looks up a named instance profile from the Instance Meta-Data Service (IMDS).                                                                                                                                                                  |+    |                   | `fromDefaultInstanceProfile` | None - selects the first instance profile, like the `discover` process does as one of its steps.                                                                                                                                                        |+    | `FromFile`        | `fromFilePath`               | `Text` (profile name), `FilePath` (credentials file), `FilePath` (config file). **Significantly improved** - now respects the `role_arn` setting in config files, alongside either `source_profile`, `credential_source`, or `web_identity_token_file`. |+    |                   | `fromFileEnv`                | None - read config files from their default location, and respects the `AWS_PROFILE` environment variable.                                                                                                                                              |+    |                   | `fromAssumedRole`            | `Text` (role arn), `Text` (role session name). Assumes a role using `sts:AssumeRole`.                                                                                                                                                                   |+    |                   | `fromSSO`                    | `FilePath` (cached token file), `Region` (SSO region), `Text` (account id), `Text` (role name). Assumes a role using `sso:GetRoleCredentials` and the cached JWT created by `aws sso login`.                                                            |+    |                   | `fromWebIdentity`            | `FilePath` (web identity token file), `Text` (role arn), `Maybe Text` (role session name). Assumes a role using `sts:AssumeRoleWithWebIdentity`.                                                                                                        |+    | `FromWebIdentity` | `fromWebIdentityEnv`         | None - reads `AWS_WEB_IDENTITY_TOKEN_FILE`, `AWS_ROLE_ARN`, and `AWS_ROLE_SESSION_NAME`.                                                                                                                                                                |+    |                   | `fromContainer`              | `Text` (absolute url to query the ECS Container Agent).                                                                                                                                                                                                 |+    | `FromContainer`   | `fromContainerEnv`           | None - reads `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI`.                                                                                                                                                                                                  |+    | `Discover`        | `discover`                   | A rough mimic of the offical SDK, trying several methods in sequence.                                                                                                                                                                                   |++  - The `Amazonka.Auth.runCredentialChain` function allows you to build your own custom credential chains.++- Select parts of `amazonka-core:Amazonka.Data` are now re-exported from `amazonka-core:Amazonka.Core` (and by extension, `amazonka:Amazonka`), instead of the entire module. [\#851](https://github.com/brendanhay/amazonka/pull/851).++  - In particular, serialisation classes and helpers are no longer exported, and service bindings import `Amazonka.Data` directly.+  - Most library users should see little difference, but the `ToText` and `ToByteString` classes are no longer exported by default.++- Records within the `amazonka-core` and `amazonka` libraries no longer have (inconsistent) leading underscores or prefixes [\#844](https://github.com/brendanhay/amazonka/pull/844). A few other functions were renamed/removed for consistency or to avoid name clashes:++  - `Amazonka.Env.envAuthMaybe` -> `Amazonka.authMaybe` (and its re-export from `Amazonka`)+  - `Amazonka.Env.configure` -> `Amazonka.Env.configureService` (and its re-export from `Amazonka`)+  - `Amazonka.Env.override` -> `Amazonka.Env.overrideService` (and its re-export from `Amazonka`)+  - `Amazonka.Env.timeout` -> `Amazonka.Env.globalTimeout` (and its re-export from `Amazonka`)+  - `Amazonka.Env.within`: removed; it was merely a record update+  - `Amazonka.Body._Body`: removed.++  As with record fields in generated bindings, you should use record updates, generic lenses/optics, or `-XOverloadedRecordDot`. However, if you prefer explicit lenses, prefixed lenses are available where the records are defined, and are colleced in the `Amazonka.Core.Lens` and `Amazonka.Lens` modules (`Amazonka.Lens` re-exports `Amazonka.Core.Lens`).++### New libraries++- `amazonka-appconfigdata`: The data plane APIs your application uses to retrieve configuration data. [Overview](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/Welcome.html#Welcome_AWS_AppConfig_Data)+- `amazonka-amplifyuibuilder`: A programmatic interface for creating and configuring user interface (UI) component libraries and themes for use in your Amplify applications. [Overview](https://docs.aws.amazon.com/amplifyuibuilder/latest/APIReference/Welcome.html)+- `amazonka-arc-zonal-shift`: Zonal shift is a function within the Amazon Route 53 Application Recovery Controller (Route 53 ARC). With zonal shifting, you can shift your load balancer resources away from an impaired Availability Zone with a single action. [Overview](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/zonal-shift.html)+- `amazonka-backupgateway`: Backup gateway is downloadable AWS Backup software that you deploy to your VMware infrastructure to connect your VMware VMs to AWS Backup.+- `amazonka-backupstorage`+- `amazonka-billingconductor`: The AWS Billing Conductor is a customizable billing service, allowing you to customize your billing data to match your desired business structure. [Overview](https://aws.amazon.com/aws-cost-management/aws-billing-conductor/)+- `amazonka-chime-sdk-media-pipelines`: Create Amazon Chime SDK media pipelines and capture audio, video, events, and data messages from Amazon Chime SDK meetings. [Overview](https://docs.aws.amazon.com/chime-sdk/latest/APIReference/API_Operations_Amazon_Chime_SDK_Media_Pipelines.html)+- `amazonka-chime-sdk-meetings`: Create Amazon Chime SDK meetings, set the AWS Regions for meetings, create and manage users, and send and receive meeting notifications. [Overview](https://docs.aws.amazon.com/chime-sdk/latest/APIReference/API_Operations_Amazon_Chime_SDK_Meetings.html)+- `amazonka-chime-sdk-voice`: Add telephony capabilities to custom communication solutions, including SIP infrastructure and Amazon Chime SDK Voice Connectors. [Overview](https://docs.aws.amazon.com/chime-sdk/latest/APIReference/API_Operations_Amazon_Chime_SDK_Voice.html)+- `amazonka-connectcampaigns`: Create high-volume outbound campaigns. For example, you may want to use this functionality for appointment reminders, telemarketing, subscription renewals, or debt collection. [Overview](https://docs.aws.amazon.com/connect-outbound/latest/APIReference/Welcome.html)+- `amazonka-connectcases`: Track and manage customer issues that require multiple interactions, follow-up tasks, and teams in your contact center. [Overview](https://aws.amazon.com/connect/cases/)+- `amazonka-controltower`: Apply the AWS library of pre-defined controls to your organizational units, programmatically. [Overview](https://docs.aws.amazon.com/controltower/latest/APIReference/Welcome.html)+- `amazonka-docdb-elastic`: Elastic Clusters enables you to elastically scale your document database to handle virtually any number of writes and reads, with petabytes of storage capacity. [Overview](https://docs.aws.amazon.com/documentdb/latest/developerguide/docdb-using-elastic-clusters.html)+- `amazonka-drs`: AWS Elastic Disaster Recovery (AWS DRS) minimizes downtime and data loss with fast, reliable recovery of on-premises and cloud-based applications using affordable storage, minimal compute, and point-in-time recovery. [Overview](https://aws.amazon.com/disaster-recovery/)+- `amazonka-emr-serverless`: Amazon EMR Serverless is a serverless option in Amazon EMR that makes it easy for data analysts and engineers to run open-source big data analytics frameworks without configuring, managing, and scaling clusters or servers. [Overview](https://aws.amazon.com/emr/serverless/)+- `amazonka-evidently`: Amazon CloudWatch Evidently lets application developers conduct experiments and identify unintended consequences of new features before rolling them out for general use, thereby reducing risk related to new feature roll-out. [Overview](https://docs.aws.amazon.com/cloudwatchevidently/latest/APIReference/Welcome.html)+- `amazonka-fsx`: Launch, run, and scale feature-rich, high-performance file systems in the cloud. [Overview](https://aws.amazon.com/fsx/)+- `amazonka-gamesparks`: Build game backends without worrying about server infrastructure. [Overview](https://aws.amazon.com/gamesparks/)+- `amazonka-inspector2`: Amazon Inspector is an automated vulnerability management service that continually scans AWS workloads for software vulnerabilities and unintended network exposure. [Overview](https://aws.amazon.com/inspector/)+- `amazonka-iot-roborunner`: Infrastructure for integrating robot systems from multiple vendors and building fleet management applications. [Overview](https://aws.amazon.com/roborunner/)+- `amazonka-iottwinmaker`: AWS IoT TwinMaker makes it easier for developers to create digital twins of real-world systems such as buildings, factories, industrial equipment, and production lines. [Overview](https://aws.amazon.com/iot-twinmaker/)+- `amazonka-ivschat`: Amazon IVS Chat is a scalable stream chat feature with a built-in moderation option designed to accompany live streaming video. [Overview](https://aws.amazon.com/ivs/features/chat/)+- `amazonka-kendra`: An intelligent search service powered by machine learning (ML) for your websites and applications. [Overview](https://aws.amazon.com/kendra/)+- `amazonka-keyspaces`: Amazon Keyspaces (for Apache Cassandra) is a scalable, highly available, and managed Apache Cassandra–compatible database service. [Overview](https://aws.amazon.com/keyspaces/)+- `amazonka-kinesis-video-webrtc-storage`: [Overview](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_Operations_Amazon_Kinesis_Video_WebRTC_Storage.html)+- `amazonka-lexv2-models`: Amazon Lex V2 is an AWS service for building conversational interfaces for applications using voice and text. This is the model building API. [Overview](https://docs.aws.amazon.com/lexv2/latest/dg/API_Types_Amazon_Lex_Model_Building_V2.html)+- `amazonka-license-manager-linux-subscriptions`: AWS License Manager provides you with the capability to view and manage commercial Linux subscriptions which you own and run on AWS. [Overview](https://docs.aws.amazon.com/license-manager/latest/userguide/linux-subscriptions.html)+- `amazonka-license-manager-user-subscriptions`: With License Manager, you can create user-based subscriptions to utilize licensed software with a per user subscription fee on Amazon EC2 instances. [Overview](https://docs.aws.amazon.com/license-manager/latest/userguide/user-based-subscriptions.html)+- `amazonka-m2`: AWS Mainframe Modernization is a set of managed tools providing infrastructure and software for migrating, modernizing, and running mainframe applications. [Overview](https://aws.amazon.com/mainframe-modernization/)+- `amazonka-migration-hub-refactor-spaces`: AWS Migration Hub Refactor Spaces is the starting point for incremental application refactoring to microservices. [Overview](https://docs.aws.amazon.com/migrationhub-refactor-spaces/latest/userguide/what-is-mhub-refactor-spaces.html)+- `amazonka-migrationhuborchestrator`: AWS Migration Hub Orchestrator simplifies and automates the migration of servers and enterprise applications to AWS. It provides a single location to run and track your migrations. [Overview](https://docs.aws.amazon.com/migrationhub-orchestrator/latest/userguide/what-is-migrationhub-orchestrator.html)+- `amazonka-migrationhubstrategy`: Migration Hub Strategy Recommendations helps you plan migration and modernization initiatives by offering migration and modernization strategy recommendations for viable transformation paths for your applications. [Overview](https://docs.aws.amazon.com/migrationhub-strategy/latest/userguide/what-is-mhub-strategy.html)+- `amazonka-oam`: Create and manage links between source accounts and monitoring accounts by using CloudWatch cross-account observability. [Overview](https://docs.aws.amazon.com/OAM/latest/APIReference/Welcome.html)+- `amazonka-omics`: Helps healthcare and life science organizations store, query, and analyze genomic, transcriptomic, and other omics data and then generate insights from that data to improve health and advance scientific discoveries. [Overview](https://aws.amazon.com/omics/)+- `amazonka-opensearchserverless`: An on-demand auto scaling configuration for Amazon OpenSearch Service. [Overview](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/serverless.html)+- `amazonka-pinpoint-sms-voice-v2`: Amazon Pinpoint is an AWS service that you can use to engage with your recipients across multiple messaging channels. The Amazon Pinpoint SMS and Voice, version 2 API provides programmatic access to options that are unique to the SMS and voice channels and supplements the resources provided by the Amazon Pinpoint API. [Overview](https://docs.aws.amazon.com/pinpoint/latest/apireference_smsvoicev2/Welcome.html)+- `amazonka-pipes`: Amazon EventBridge Pipes helps you create point-to-point integrations between event producers and consumers with optional transform, filter and enrich steps. [Overview](https://aws.amazon.com/eventbridge/pipes/)+- `amazonka-privatenetworks`:  AWS Private 5G is a managed service that makes it easier to deploy, operate, and scale your own private mobile network, with all required hardware and software provided by AWS. [Overview](https://aws.amazon.com/private5g/)+- `amazonka-rbin`: Recycle Bin is a data recovery feature that enables you to restore accidentally deleted Amazon EBS snapshots and EBS-backed AMIs. When using Recycle Bin, if your resources are deleted, they are retained in the Recycle Bin for a time period that you specify before being permanently deleted. [Overview](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/recycle-bin.html)+- `amazonka-redshift-serverless`: Amazon Redshift Serverless makes it easier to run and scale analytics without having to manage your data warehouse infrastructure. [Overview](https://aws.amazon.com/redshift/redshift-serverless/)+- `amazonka-resiliencehub`: AWS Resilience Hub provides a central place to define, validate, and track the resilience of your applications on AWS. [Overview](https://aws.amazon.com/resilience-hub/)+- `amazonka-resource-explorer-v2`: Search for and discover relevant resources across AWS. [Overview](https://aws.amazon.com/resourceexplorer/)+- `amazonka-rolesanywhere`: You can use AWS Identity and Access Management Roles Anywhere to obtain temporary security credentials in IAM for workloads such as servers, containers, and applications that run outside of AWS. [Overview](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/introduction.html)+- `amazonka-rum`: With CloudWatch RUM (Real User Monitoring), you can perform real user monitoring to collect and view client-side data about your web application performance from actual user sessions in near real time. [Overview](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-RUM.html)+- `amazonka-sagemaker-geospatial`: Build, train, and deploy ML models using geospatial data. [Overview](https://aws.amazon.com/sagemaker/geospatial/)+- `amazonka-sagemaker-metrics`: [Overview](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_Operations_Amazon_SageMaker_Metrics_Service.html)+- `amazonka-scheduler`: Amazon EventBridge Scheduler is a serverless scheduler that allows you to create, run, and manage tasks from one central, managed service. [Overview](https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html)+- `amazonka-securitylake`: Amazon Security Lake automatically centralizes security data from cloud, on-premises, and custom sources into a purpose-built data lake stored in your account. [Overview](https://aws.amazon.com/security-lake/)+- `amazonka-simspaceweaver`: A managed service that lets you create expansive simulation worlds at increased levels of complexity and scale. [Overview](https://aws.amazon.com/simspaceweaver/)+- `amazonka-sms-voice`: Looks like an alternate binding to the Pinpoint SMS and Voice API. Maybe stick with `amazonka-pinpoint-sms-voice-v2`? [Overview](https://docs.aws.amazon.com/pinpoint-sms-voice/latest/APIReference/welcome.html)+- `amazonka-ssm-sap`: Actions and data types for AWS Systems Manager for SAP.+- `amazonka-support-app`: You can use the AWS Support App to manage your AWS support cases in Slack. You can invite your team members to chat channels, respond to case updates, and chat directly with support agents. [Overview](https://docs.aws.amazon.com/awssupport/latest/user/aws-support-app-for-slack.html)+- `amazonka-timestream-query`: Amazon Timestream is a fast, scalable, and serverless time series database service for IoT and operational applications. (Write API) [Overview](https://aws.amazon.com/timestream/)+- `amazonka-timestream-write`: Amazon Timestream is a fast, scalable, and serverless time series database service for IoT and operational applications. (Write API) [Overview](https://aws.amazon.com/timestream/)+- `amazonka-wafv2`: AWS WAF is a web application firewall that helps protect your web applications or APIs against common web exploits and bots that may affect availability, compromise security, or consume excessive resources (V2 API). [Overview](https://aws.amazon.com/waf/)+- `amazonka-workspaces-web`: Amazon WorkSpaces Web is a low-cost, fully managed workspace built specifically to facilitate secure access to internal websites and software-as-a-service (SaaS) applications from existing web browsers. [Overview](https://aws.amazon.com/workspaces/web/)++### Changed++- `amazonka-core`: Use `crypton` instead of `cryptonite` to provide cryptographic primitives+[\#920](https://github.com/brendanhay/amazonka/pull/920)+- `amazonka-core`/`amazonka-redshift`/`amazonka-route53`/`amazonka-s3`: Support Melbourne region (`ap-southeast-4`).+[\#897](https://github.com/brendanhay/amazonka/pull/897)+- `amazonka`: Presigning functions do not require `MonadIO`.+[\#885](https://github.com/brendanhay/amazonka/pull/885)+- `gen` / `amazonka-*`: Sort generated code so that outputs are stable across regenerations.+[\#890](https://github.com/brendanhay/amazonka/pull/890)+- `amazonka-core`/`amazonka`: Various time-related data types and the `_Time` `Iso'` are re-exported by `Amazonka.Core` and therefore `Amazonka`.+[\#884](https://github.com/brendanhay/amazonka/pull/884)+- `amazonka-core`: service error matchers are now `AsError a => Fold a ServiceError` instead of `AsError a => Getting (First ServiceError) a ServiceError`. This makes them more flexible (e.g., usable with `Control.Lens.has`), but existing uses should be unaffected.+[\#878](https://github.com/brendanhay/amazonka/pull/878)+- `amazonka-core`: The `Logger` and `LogLevel` types and associated functions have been moved to `Amazonka.Logger`.+[\#875](https://github.com/brendanhay/amazonka/pull/875)+- `amazonka`: The `override :: Dual (Endo Service)` has been replaced by `overrides :: Service -> Service`.+[\#870](https://github.com/brendanhay/amazonka/pull/870)+- `amazonka-core`: `Endpoint` now has a `basePath :: RawPath`. Handy with `amazonka-apigatewaymanagementapi`.+[\#869](https://github.com/brendanhay/amazonka/pull/869)+- `amazonka-core`: Parse more timezone names than just `"GMT"`, per RFC822+[\#868](https://github.com/brendanhay/amazonka/pull/868)+- `amazonka-ec2`, `amazonka-route53`, `amazonka-s3`: Provide handwritten `Iso'`s and `Lens'`s for manually-written types, that match the new generator's conventions+[\#859](https://github.com/brendanhay/amazonka/pull/859)+- `amazonka-redshift`: Deprecate `getAccountId` as Redshift uses service-principal credentials to deliver logs to S3. Also provide `getCloudTrailAccountId`+[\#858](https://github.com/brendanhay/amazonka/pull/858)+- `amazonka-route53`: Return Hosted Zone ID for S3 websites in all regions+[\#858](https://github.com/brendanhay/amazonka/pull/858)+- `amazonka-s3`: Correctly return dotted S3 website hostnames in those regions+[\#858](https://github.com/brendanhay/amazonka/pull/858)+- `amazonka-core`: Add regions: `Hyderabad` (`ap-south-2`), `Jakarta` (`ap-southeast-3`), `Spain` (`eu-south-2`), `Zurich` (`eu-central-2`), and `UAE` (`me-central-1`)+[\#858](https://github.com/brendanhay/amazonka/pull/858)+- `amazonka`: Update EC2 metadata keys based on [instance metadata categories](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html)+[\#837](https://github.com/brendanhay/amazonka/pull/837)+- `amazonka-dynamodb`: Provide a sum type for `WriteRequest`+[\#799](https://github.com/brendanhay/amazonka/pull/799)+- `amazonka-sso`: replace `SessionTokenType` with `Core.SessionToken`+[\#792](https://github.com/brendanhay/amazonka/pull/792)+- `amazonka-sso`: Use `amazonka-core` types in `GetRoleCredentials` response+[\#791](https://github.com/brendanhay/amazonka/pull/791)+- `amazonka-sts`: Mark `Credentials` as required in `AssumeRole*` responses+[\#791](https://github.com/brendanhay/amazonka/pull/791)+- `amazonka-sso`: Mark `RoleCredentials_{accessKeyId,secretAccessKey}` as required+[\#789](https://github.com/brendanhay/amazonka/pull/789)+- `amazonka-core`: urldecode query string parts when parsing to `QueryString`+[\#780](https://github.com/brendanhay/amazonka/pull/769)+- `amazonka-dynamodb`, `amazonka-dynamodb-streams`: Fix deserialisation of booleans+[\#775](https://github.com/brendanhay/amazonka/pull/775)+- `amazonka`: Add a public interface to send unsigned requests. Sending functions are now defined in `Amazonka.Send`, but are re-exported from `Amazonka`.+[\#769](https://github.com/brendanhay/amazonka/pull/769)+- `amazonka-sso`: Mark `GetRoleCredentialsResponse_roleCredentials` as required+[\#759](https://github.com/brendanhay/amazonka/pull/759)+- `amazonka-dynamodb`: Mark various fields as required+[\#724](https://github.com/brendanhay/amazonka/pull/724)+- `amazonka-dynamodb`: Provide a sum type for `AttributeValue`+[\#724](https://github.com/brendanhay/amazonka/pull/724)+- `amazonka-dynamodb-streams`: Provide a sum type for `AttributeValue`+[\#724](https://github.com/brendanhay/amazonka/pull/724)+- `amazonka`: SSO authentication support (thanks @pbrisbin)+[\#757](https://github.com/brendanhay/amazonka/pull/757)+- `amazonka`: Use IMDSv2 for metadata requests on EC2 (thanks @pbrisbin)+[\#831](https://github.com/brendanhay/amazonka/pull/831)++### Fixed++- `amazonka-core`: Stop calling `iso8601DateFormat` and using `*` to mean `Data.Kind.Type`+[\#885](https://github.com/brendanhay/amazonka/pull/885),+[\#892](https://github.com/brendanhay/amazonka/pull/892)+- `amazonka-s3`: Properly format timestamps+[\#881](https://github.com/brendanhay/amazonka/pull/881)+- `gen`: Take per-shape `timestampFormat` annotations into account.+[\#882](https://github.com/brendanhay/amazonka/pull/882)+- `amazonka-core`: Only consider 2xx and 304 responses as successful+[\#835](https://github.com/brendanhay/amazonka/pull/835)+- `amazonka-core`: Allow customisation of S3 addressing styles like Boto 3 can (thanks @basvandijk, @ivb-supercede)+[\#832](https://github.com/brendanhay/amazonka/pull/832)+- `amazonka-core`: Correctly split error-codes-in-headers at the first colon+[\#830](https://github.com/brendanhay/amazonka/pull/830)+- `amazonka-core`: Correctly double-url-encode request paths when computing V4 signatures+[\#812](https://github.com/brendanhay/amazonka/pull/812)+- `amazonka-core`: Correctly compute body length for `hashedFileRange`+[\#794](https://github.com/brendanhay/amazonka/pull/794)+- Generator: Correctly generate `ToJSON` instances for requests which set a `"payload":` field in `"type": "structure"` definitions.+[\#790](https://github.com/brendanhay/amazonka/pull/790)+  - Fixes some API calls in `amazonka-glacier` and `amazonka-pinpoint`+- Background credential refresh now waits until five minutes before token expiry (or halfway to expiry if it expires sooner than that) to avoid the risk of expired credentials.+[\#747](https://github.com/brendanhay/amazonka/pull/783)+- Presigning URLs that are not for S3+[\#767](https://github.com/brendanhay/amazonka/pull/767)+- `amazonka-s3`/`amazonka-glacier`: treat upload IDs are a mandatory part of the `CreateMultipartUpload`/`InitiateMultipartUpload` responses.+[\#725](https://github.com/brendanhay/amazonka/pull/725)+- Hosted Zone IDs for S3 website endpoints are correct for all regions.+[\#723](https://github.com/brendanhay/amazonka/pull/723)+- `amazonka-ssm`: Various fields that are always available are no longer Maybe's.+[\#741](https://github.com/brendanhay/amazonka/pull/741)+- `amazonka-core`: to be compatible with mtl-2.3, avoid `Alternative (Either String)`+[\#779](https://github.com/brendanhay/amazonka/pull/779)++## [2.0.0 RC1](https://github.com/brendanhay/amazonka/tree/2.0.0-rc1)+Released: **28nd November, 2021**, Compare: [1.6.1](https://github.com/brendanhay/amazonka/compare/1.6.1...2.0.0-rc1)++### Major Changes++- Every service has been regenerated.++- Enums (sum types) have been replaced with pattern synonyms. (Thanks @rossabaker)+  - This reduces GHC memory usage on some large packages (notably `amazonka-ec2`), as well as makes them more robust against new enum values in regions, responses, etc.++- Naming+  - Record smart constructors (previously `describeInstances`, `getObject`, etc.) are now strictly prefixed with `new`, such as `newDescribeInstances`.+  - Record fields are no longer prefixed and are fully exported.+  - Generated lenses are no longer exported from the top-level `Amazonka.<name>` module - instead a `Amazonka.<name>.Lens` module is provided for backwards compatibility. These lenses may be deprecated in future.+  - Generated lenses no longer use mnemonic or heuristically assigned prefixes such as `dirsrsInstances` and instead strictly prefix using the type name `describeInstances_instances` - following the form `<type>_<field>`.+  - A library such as [`generic-lens`](https://hackage.haskell.org/package/generic-lens) or [`optics`](https://hackage.haskell.org/package/optics) can be used with the type's `Generic` instance for more succinct lenses that match the record field name or AWS documentation.++- Exports+  - The `amazonka` package now re-exports modules from `amazonka-core` such as `Amazonka.Data`, `Amazonka.Types`.+  - All generated datatype constructors are fully exported. The datatype constructor is strictly prime suffixed, so for a given type `data <type> = <type>'`.++- CI+  - Nix, Bazel, and GitHub Actions are used for CI.+  - CPP supporting GHC < 8.8 has been removed.+  - While GHC 8.6 is not in the CI matrix, it currently builds, so packages depend on `base >= 4.12`.++- The `AWST` transformer from `Control.Monad.Trans.AWS` and its related instances has been removed. Functions such as `send` and `paginate` now universally take an `Env` as their first argument, so you can build your own transformer, or use your preferred effects system.++- Namespace+  - The core `Network.AWS` namespace has been renamed to `Amazonka`, which now matches the package name. A simple search and replace on your codebase should be sufficient for migration:++```+perl -pi -e 's/Network\.AWS/Amazonka/g' `find . -type f -name '*.hs'`+```++### Fixed++- `aeson ^>= 1.5` and `aeson ^>= 2.0` are now supported.+[\#713](https://github.com/brendanhay/amazonka/pull/713)+- The `Credentials` type has a new `FromWebIdentity` constructor. Thank you to Mateusz Kowalczyk (@Fuuzetsu) and Oleg (@K0Te) for the initial implementation.+[\#708](https://github.com/brendanhay/amazonka/pull/708)+- It is now possible to make unsigned requests. Useful for [`sts:AssumeRoleWithWebIdentity`](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html)+[\#708](https://github.com/brendanhay/amazonka/pull/708)+- Fix trailing slash bug in gen model+[\#528](https://github.com/brendanhay/amazonka/pull/528)+- Close connections immediately (when we know that we can)+[\#493](https://github.com/brendanhay/amazonka/pull/493)+- Remove the Content-Length header when doing V4 streaming signatures+[\#547](https://github.com/brendanhay/amazonka/pull/547)+- Ensure that KerberosAttributes is parsed correctly from an empty response+[\#512](https://github.com/brendanhay/amazonka/pull/512)+- Correct Stockholm in FromText Region+[\#565](https://github.com/brendanhay/amazonka/pull/572)+- Fix MonadUnliftIO compiler errors on ghc-8.10.1+[\#572](https://github.com/brendanhay/amazonka/pull/572)+- Deduplicate CreateCertificateFromCSR fixtures+[\#500](https://github.com/brendanhay/amazonka/pull/500)+- CloudFormation ListChangeSets and DescribeChangeSets are paginated+[\#620](https://github.com/brendanhay/amazonka/pull/620)+- Use `signingName`, not `endpointPrefix`, when signing requests+[\#622](https://github.com/brendanhay/amazonka/pull/622)+- Add `x-amz-glacier-version` to glacier headers (and extend generator to let `operationPlugins` support wildcards)+[\#623](https://github.com/brendanhay/amazonka/pull/623)+- Add required fields for Glacier multipart uploade+[\#624](https://github.com/brendanhay/amazonka/pull/624)+- If nonstandard ports are used, include them in signed host header+[\#625](https://github.com/brendanhay/amazonka/pull/625)+- Duplicate files that differ only in case have been removed+[\#637](https://github.com/brendanhay/amazonka/pull/637)+- S3 object sizes are now `Integer` instead of `Int`+[\#649](https://github.com/brendanhay/amazonka/pull/649)+- Fix getting regions from named profiles+[\#654](https://github.com/brendanhay/amazonka/pull/654)+- amazonka-rds now supports the `DestinationRegion` pseudo-parameter for cross-region requests+[\#661](https://github.com/brendanhay/amazonka/pull/661)+- Fixed S3 envelope encryption+[\#669](https://github.com/brendanhay/amazonka/pull/669)+- Fixed S3 to use vhost endpoints, parse `LocationConstraint`s properly, and ensure `Content-MD5` header correctly set.+[\#673](https://github.com/brendanhay/amazonka/pull/673)+- Fixed S3 to not set empty `Content-Encoding`, and to be able to set `Content-Encoding` without breaking signing+[\#681](https://github.com/brendanhay/amazonka/pull/681)++### Other Changes++- Bump the upper bound in the dependency on http-client+[\#526](https://github.com/brendanhay/amazonka/pull/526)+- Added new regions to ELB, RedShift, Route53.+[\#541](https://github.com/brendanhay/amazonka/pull/541)+- Update service definitions for cloudwatch-events+[\#544](https://github.com/brendanhay/amazonka/pull/544)+- Add MonadFail instance for AWST+[\#551](https://github.com/brendanhay/amazonka/pull/551)+- Add an instance for `PrimMonad m => PrimMonad (AWST' r m)`+[\#510](https://github.com/brendanhay/amazonka/pull/510)+- Set startedAt as optional in AWS batch+[\#561](https://github.com/brendanhay/amazonka/pull/561)+- Add `ignoredPaginators` to service definition.+[\#578](https://github.com/brendanhay/amazonka/pull/578)+- Adds paginators to AWS Secrets Manager API+[\#576](https://github.com/brendanhay/amazonka/pull/576)+- Add intelligent tiering S3 type+[\#570](https://github.com/brendanhay/amazonka/pull/570)+- AWS service descriptions appear in haddocks+[\#619](https://github.com/brendanhay/amazonka/pull/619)+- Drop some `MonadThrow` and `MonadCatch` constraints+[\#626](https://github.com/brendanhay/amazonka/pull/626)+- Use an in-tree script to generate services, instead of pulling the repo into the Nix store+[\#639](https://github.com/brendanhay/amazonka/pull/639)+- Provide script to audit missing service configurations from boto+[\#644](https://github.com/brendanhay/amazonka/pull/644)++### New libraries++- `amazonka-apigatewaymanagementapi`: API for backends to interact with active WebSocket connections on a deployed API Gateway. [Developer Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html)+- `amazonka-eks`: Amazon Elastic Kubernetes Service (Amazon EKS) is a managed container service to run and scale Kubernetes applications in the cloud or on-premises. [Overview](https://aws.amazon.com/eks/)+[\#618](https://github.com/brendanhay/amazonka/pull/618)+- `amazonka-qldb`: Fully managed ledger database that provides a transparent, immutable, and cryptographically verifiable transaction log. Owned by a central trusted authority. [Overview](https://aws.amazon.com/qldb/)+[\#621](https://github.com/brendanhay/amazonka/pull/621)+- `amazonka-sesv2`: High-scale inbound and outbound cloud email service --- V2 API. [Overview](https://aws.amazon.com/ses/)+[\#633](https://github.com/brendanhay/amazonka/pull/633)+- `amazonka-textract`: Easily extract printed text, handwriting, and data from any document. [Overview](https://aws.amazon.com/textract/)+- `amazonka-accessanalyzer`: Help identify potential resource-access risks by enabling you to identify any policies that grant access to an external principal. [Overview](https://docs.aws.amazon.com/access-analyzer/latest/APIReference/Welcome.html)+- `amazonka-account`: API operations to modify an AWS account itself. [Overview](https://docs.aws.amazon.com/access-analyzer/latest/APIReference/Welcome.html)+- `amazonka-amp`: A managed Prometheus-compatible monitoring and alerting service that makes it easy to monitor containerized applications and infrastructure at scale. [Overview](https://aws.amazon.com/prometheus/)+- `amazonka-amplify`: Purpose-built tools and services that make it quick and easy for front-end web and mobile developers build full-stack applications on AWS. [Overview](https://aws.amazon.com/amplify/)+- `amazonka-amplifybackend`: Programmatic interface to the AWS Amplify Admin UI. [Overview](https://docs.aws.amazon.com/amplify-admin-ui/latest/APIReference/what-is-admin-ui.html)+- `amazonka-apigatewayv2`: Version 2 of the API Gateway API, for HTTP and WebSocket APIs. [Overview](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/api-reference.html)+- `amazonka-appconfig`: A feature of AWS Systems Manager, to make it easy to quickly and safely configure, validate, and deploy application configurations. [Overview](https://aws.amazon.com/systems-manager/features/appconfig)+- `amazonka-appflow`: Fully managed integration service that securely transfers data between Software-as-a-Service (SaaS) applications and AWS services. [Overview](https://aws.amazon.com/appflow/)+- `amazonka-appintegrations`: Configure and connect external applications to Amazon Connect. [Overview](https://docs.aws.amazon.com/appintegrations/latest/APIReference/Welcome.html)+- `amazonka-application-insights`: Facilitates observability for applications and their underlying AWS resources. [Overview](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html)+- `amazonka-applicationcostprofiler`: Track the consumption of shared AWS resources used by software applications and report granular cost breakdown across tenant base. [Overview](https://aws.amazon.com/aws-cost-management/aws-application-cost-profiler/)+- `amazonka-appmesh`: Service mesh that provides application-level networking for services to communicate with each other across multiple types of compute infrastructure. [Overview](https://aws.amazon.com/app-mesh/)+- `amazonka-apprunner`: Fully managed container application service. [Overview](https://aws.amazon.com/apprunner/)+- `amazonka-auditmanager`: Continuously audit AWS usage to simplify risk assessment and compliance. [Overview](https://aws.amazon.com/audit-manager/)+- `amazonka-backup`: Centrally manage and automate backups across AWS services. [Overview](https://aws.amazon.com/backup/)+- `amazonka-braket`: Managed quantum computing service. [Overview](https://aws.amazon.com/braket/)+- `amazonka-chime-sdk-identity`: Integrate identity providers with Amazon Chime SDK Messaging. [Overview](https://docs.aws.amazon.com/chime/latest/APIReference/API_Operations_Amazon_Chime_SDK_Identity.html)+- `amazonka-chime-sdk-messaging`: Create messaging applications that run on the Amazon Chime service. [Overview](https://docs.aws.amazon.com/chime/latest/dg/using-the-messaging-sdk.html)+- `amazonka-chime`: Communications service that lets you meet, chat, and place business calls inside and outside your organization, all using a single application. [Overview](https://aws.amazon.com/chime/)+- `amazonka-cloudcontrol`: Create, read, update, delete, and list (CRUD-L) your cloud resources that belong to a wide range of services—both AWS and third-party. [Overview](https://docs.aws.amazon.com/cloudcontrolapi/latest/userguide/what-is-cloudcontrolapi.html)+- `amazonka-codeartifact`: Managed artifact repository service to securely store, publish, and share software packages. [Overview](https://aws.amazon.com/codeartifact/)+- `amazonka-codeguru-reviewer`: Program analysis and machine learning service to detect potential defects and improvements in Java and Python code. [Overview](https://docs.aws.amazon.com/codeguru/latest/reviewer-ug/welcome.html)+- `amazonka-codeguruprofiler`: Collects runtime performance data from applications, and provides recommendations to help fine-tune application performance. [Overview](https://docs.aws.amazon.com/codeguru/latest/profiler-ug/what-is-codeguru-profiler.html)+- `amazonka-codestar-connections`: Connect services like AWS CodePipeline to third-party source code providers. [Overview](https://docs.aws.amazon.com/codestar-connections/latest/APIReference/Welcome.html)+- `amazonka-codestar-notifications`: Subscribe to events from AWS CodeBuild, AWS CodeCommit, AWS CodeDeploy, and AWS CodePipeline. [Overview](https://docs.aws.amazon.com/codestar-notifications/latest/APIReference/Welcome.html)+- `amazonka-comprehendmedical`: Extract information from unstructured medical text. [Overview](https://aws.amazon.com/comprehend/medical/)+- `amazonka-compute-optimizer`: Recommends optimal AWS resources to reduce costs and improve performance. [Overview](https://aws.amazon.com/compute-optimizer/)+- `amazonka-connect-contact-lens`: Undertand the sentiment and trends of customer conversations to identify crucial company and product feedback. [Overview](https://aws.amazon.com/connect/contact-lens/)+- `amazonka-connectparticipant`: Amazon Connect APIs for chat participants, such as agents and customers. [Overview](https://docs.aws.amazon.com/connect-participant/latest/APIReference/Welcome.html)+- `amazonka-customer-profiles`: Unified view of customer profiles in Amazon Connect. [Overview](https://aws.amazon.com/connect/customer-profiles/)+- `amazonka-databrew`: Visual data preparation tool for data analysts and data scientists to clean and normalize data. [Overview](https://aws.amazon.com/glue/features/databrew/)+- `amazonka-dataexchange`: Easily find and subscribe to third-party data in the cloud. [Overview](https://aws.amazon.com/data-exchange/)+- `amazonka-datasync`: Connect to your storage, connect to our storage, and start copying. [Overview](https://aws.amazon.com/datasync/)+- `amazonka-detective`: Analyze and visualize security data to get to the root cause of potential security issues. [Overview](https://aws.amazon.com/detective/)+- `amazonka-devops-guru`: ML-powered cloud operations service to improve application availability. [Overview](https://aws.amazon.com/devops-guru/)+- `amazonka-dlm`: Data Lifecycle Manager --- manage the lifecycle of your AWS resources. [Overview](https://docs.aws.amazon.com/dlm/latest/APIReference/Welcome.html)+- `amazonka-docdb`: Managed document database service. [Overview](https://aws.amazon.com/documentdb/)+- `amazonka-ebs`: High performance block storage. [Overview](https://aws.amazon.com/ebs/)+- `amazonka-ec2-instance-connect`: Connect to Linux EC2 instances using SSH. [Overview](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Connect-using-EC2-Instance-Connect.html)+- `amazonka-ecr-public`: Public, managed container image registry service. [Overview](https://docs.aws.amazon.com/AmazonECRPublic/latest/APIReference/Welcome.html)+- `amazonka-elastic-inference`: Attach low-cost GPU-powered acceleration to Amazon EC2 and Sagemaker instances or Amazon ECS tasks. [Overview](https://aws.amazon.com/machine-learning/elastic-inference/)+- `amazonka-emr-containers`: Amazon EMR on EKS. [Overview](https://docs.aws.amazon.com/emr-on-eks/latest/APIReference/Welcome.html)+- `amazonka-finspace-data`: Data operations for Amazon FinSpace. [Overview](https://docs.aws.amazon.com/finspace/latest/data-api/fs-api-welcome.html)+- `amazonka-finspace`: Data management and analytics service purpose-built for the financial services industry. [Overview](https://aws.amazon.com/finspace/)+- `amazonka-fis`: `us-east-1` as a service. [Overview](https://aws.amazon.com/fis/)+- `amazonka-forecast`: Time-series forecasting service based on machine learning, and built for business metrics analysis. [Overview](https://aws.amazon.com/forecast/)+- `amazonka-forecastquery`: Amazon Forecast Query Service. [Overview](https://docs.aws.amazon.com/forecast/latest/dg/API_Operations_Amazon_Forecast_Query_Service.html)+- `amazonka-frauddetector`: Managed fraud detection service using machine learning to identify potentially fraudulent activities and catch fraud faster. [Overview](https://aws.amazon.com/fraud-detector/)+- `amazonka-globalaccelerator`: Improve global application availability and performance using the AWS global network. [Overview](https://aws.amazon.com/global-accelerator/)+- `amazonka-grafana`: Managed service for the Grafana analytics platform. [Overview](https://aws.amazon.com/grafana/)+- `amazonka-greengrassv2`: [Overview](https://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-v2-whats-new.html)+- `amazonka-groundstation`: Control satellites and ingest data with fully managed Ground Station as a Service. [Overview](https://aws.amazon.com/ground-station/)+- `amazonka-healthlake`: Securely store, transform, query, and analyze health data. [Overview](https://aws.amazon.com/healthlake/)+- `amazonka-honeycode`: Quickly build mobile and web apps for teams—without programming. [Overview](https://honeycode.aws)+- `amazonka-identitystore`: AWS Single Sign-On (SSO) Identity Store. [Overview](https://docs.aws.amazon.com/singlesignon/latest/IdentityStoreAPIReference/welcome.html)+- `amazonka-imagebuilder`: AWS EC2 Image Builder --- Automate the creation, management, and deployment of customized, secure, and up-to-date server images. [Overview](https://docs.aws.amazon.com/imagebuilder/latest/userguide/what-is-image-builder.html)+- `amazonka-iot1click-devices`:  [Overview](https://docs.aws.amazon.com/iot-1-click/1.0/devices-apireference/what-is-iot.html)+- `amazonka-iot1click-projects`: [Overview](https://docs.aws.amazon.com/iot-1-click/latest/projects-apireference/Welcome.html)+- `amazonka-iotdeviceadvisor`: Managed cloud-based test capability to validate IoT devices for reliable and secure connectivity with AWS IoT Core. [Overview](https://aws.amazon.com/iot-core/device-advisor/)+- `amazonka-iotevents-data`: Send inputs to detectors, list detectors, and view or update a detector's status. [Overview](https://docs.aws.amazon.com/iotevents/latest/apireference/Welcome.html)+- `amazonka-iotevents`: Easily detect and respond to events from IoT sensors and applications. [Overview](https://aws.amazon.com/iot-events/)+- `amazonka-iotfleethub`: Build standalone web applications for monitoring the health of your device fleets. [Overview](https://docs.aws.amazon.com/iot/latest/fleethubuserguide/what-is-aws-iot-monitor.html)+- `amazonka-iotfleetwise`: Collect, transform, and transfer vehicle data to the cloud in near real time. [Overview](https://aws.amazon.com/iot-fleetwise/)+- `amazonka-iotsecuretunneling`: Establish bidirectional communication to remote devices over a secure connection that is managed by AWS IoT. [Overview](https://docs.aws.amazon.com/iot/latest/developerguide/secure-tunneling.html)+- `amazonka-iotsitewise`: Collect, organize, and analyze data from industrial equipment at scale. [Overview](https://aws.amazon.com/iot-sitewise/)+- `amazonka-iotthingsgraph`: Visually develop IoT applications. [Overview](https://aws.amazon.com/iot-things-graph/)+- `amazonka-iotwireless`: Connect, manage, and secure LoRaWAN devices at scale. [Overview](https://aws.amazon.com/iot-core/lorawan/)+- `amazonka-ivs`: Live streaming solution, ideal for creating interactive video experiences. [Overview](https://aws.amazon.com/ivs/)+- `amazonka-kafka`: Control plane operations for Amazon Managed Streaming for Apache Kafka. [Overview](https://aws.amazon.com/msk/what-is-kafka/)+- `amazonka-kafkaconnect`: Deploy fully managed connectors built for Kafka Connect. [Overview](https://docs.aws.amazon.com/msk/latest/developerguide/msk-connect.html)+- `amazonka-kinesis-video-signaling`: Kinesis Video Streams with WebRTC. [Overview](https://docs.aws.amazon.com/kinesisvideostreams-webrtc-dg/latest/devguide/what-is-kvswebrtc.html)+- `amazonka-kinesisanalyticsv2`: Managed service that you can use to process and analyze streaming data. [Overview](https://docs.aws.amazon.com/kinesisanalytics/latest/apiv2/Welcome.html)+- `amazonka-lakeformation`: Build a secure data lake in days. [Overview](https://aws.amazon.com/lake-formation/)+- `amazonka-license-manager`: Set rules to manage, discover, and report software license usage. [Overview](https://aws.amazon.com/license-manager/)+- `amazonka-location`: Securely and easily add location data to applications. [Overview](https://aws.amazon.com/location/)+- `amazonka-lookoutequipment`: Detect abnormal equipment behavior by analyzing sensor data. [Overview](https://aws.amazon.com/lookout-for-equipment/)+- `amazonka-lookoutmetrics`: Automatically detect anomalies in metrics and identify their root cause. [Overview](https://aws.amazon.com/lookout-for-metrics/)+- `amazonka-lookoutvision`: Spot product defects using computer vision to automate quality inspection. [Overview](Spot product defects using computer vision to automate quality inspection)+- `amazonka-macie`: Amazon Macie Classic. [Overview](https://docs.aws.amazon.com/macie/latest/userguide/what-is-macie.html)+- `amazonka-macie2`: Discover and protect your sensitive data at scale. [Overview](https://aws.amazon.com/macie/)+- `amazonka-managedblockchain`: Easily create and manage scalable blockchain networks. [Overview](https://aws.amazon.com/managed-blockchain/)+- `amazonka-marketplace-catalog`: [Overview](https://docs.aws.amazon.com/marketplace-catalog/latest/api-reference/welcome.html)+- `amazonka-mediaconnect`: Secure, reliable live video transport. [Overview](https://aws.amazon.com/mediaconnect/)+- `amazonka-mediapackage-vod`: [Overview](https://docs.aws.amazon.com/mediapackage/latest/ug/vod-content.html)+- `amazonka-mediatailor`: Linear channel assembly and personalized ad-insertion. [Overview](https://aws.amazon.com/mediatailor/)+- `amazonka-memorydb`: Redis-compatible, durable, in-memory database service. [Overview](https://aws.amazon.com/memorydb/)+- `amazonka-mgn`: AWS Application Migration Service. [Overview](https://aws.amazon.com/application-migration-service/)+- `amazonka-migrationhub-config`: [Overview](https://docs.aws.amazon.com/migrationhub-home-region/latest/APIReference/Welcome.html)+- `amazonka-mwaa`: Highly available, secure, and managed workflow orchestration for Apache Airflow. [Overview](https://aws.amazon.com/managed-workflows-for-apache-airflow/)+- `amazonka-neptune`: Build and run graph applications with highly connected datasets. [Overview](https://aws.amazon.com/neptune/)+- `amazonka-network-firewall`: Deploy network security across your Amazon VPCs. [Overview](https://aws.amazon.com/network-firewall/)+- `amazonka-networkmanager`: Create a global network in which you can monitor your AWS and on-premises networks that are built around transit gateways. [Overview](https://docs.aws.amazon.com/networkmanager/latest/APIReference/Welcome.html)+- `amazonka-nimble`: Empower creative studios to produce visual effects, animation, and interactive content entirely in the cloud. [Overview](https://aws.amazon.com/nimble-studio/)+- `amazonka-opensearch`: Distributed, open-source search and analytics suite. (Successor to Amazon Elasticsearch Service.) [Overview](https://aws.amazon.com/opensearch-service/the-elk-stack/what-is-opensearch/)+- `amazonka-outposts`: Run AWS infrastructure and services on premises. [Overview](https://aws.amazon.com/outposts/)+- `amazonka-panorama`: Improve your operations with computer vision at the edge. [Overview](https://aws.amazon.com/panorama/)+- `amazonka-personalize-events`: Event ingestion for Amazon Personalize. [Overview](https://docs.aws.amazon.com/personalize/latest/dg/recording-events.html)+- `amazonka-personalize-runtime`: [Overview](https://docs.aws.amazon.com/personalize/latest/dg/API_Operations_Amazon_Personalize_Runtime.html)+- `amazonka-personalize`: Create real-time personalized user experiences faster at scale. [Overview](https://aws.amazon.com/personalize/)+- `amazonka-pi`: Analyze and tune Amazon RDS database performance. [Overview](https://aws.amazon.com/rds/performance-insights/)+- `amazonka-pinpoint-email`: [Overview](https://docs.aws.amazon.com/pinpoint-email/latest/APIReference/Welcome.html)+- `amazonka-pinpoint-sms-voice`: [Overview](https://docs.aws.amazon.com/pinpoint-sms-voice/latest/APIReference/welcome.html)+- `amazonka-proton`: Automate management for container and serverless deployments. [Overview](https://aws.amazon.com/proton/)+- `amazonka-qldb-session`: [Overview](https://docs.aws.amazon.com/qldb/latest/developerguide/API_Operations_Amazon_QLDB_Session.html)+- `amazonka-quicksight`: Scalable, serverless, embeddable, ML-powered BI service. [Overview](https://aws.amazon.com/quicksight/)+- `amazonka-ram`: Securely share your resources across AWS accounts, organizational units (OUs), and with IAM users and roles. [Overview](https://aws.amazon.com/ram/)+- `amazonka-rds-data`: Run SQL statements on Amazon Aurora Serverless DB cluster. [Overview](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html)+- `amazonka-redshift-data`: Access Amazon Redshift data over HTTPS. [Overview](https://docs.aws.amazon.com/redshift/latest/mgmt/data-api.html)+- `amazonka-robomaker`: Run, scale, and automate robotics simulation. [Overview](https://aws.amazon.com/robomaker/)+- `amazonka-route53-recovery-cluster`: Simplify and automate recovery for highly available applications. [Overview](https://aws.amazon.com/route53/application-recovery-controller/)+- `amazonka-route53-recovery-control-config`: [Overview](https://docs.aws.amazon.com/recovery-cluster/latest/api/what-is-recovery-control.html)+- `amazonka-route53-recovery-readiness`: [Overview](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/route53-recovery-readiness/index.html)+- `amazonka-route53resolver`: [Overview](https://docs.aws.amazon.com/Route53/latest/APIReference/API_Operations_Amazon_Route_53_Resolver.html)+- `amazonka-s3outposts`: Object storage in your on-premises environments. [Overview](https://aws.amazon.com/s3/outposts/)+- `amazonka-sagemaker-a2i-runtime`: Add human judgment to any machine learning application. [Overview](https://docs.aws.amazon.com/augmented-ai/2019-11-07/APIReference/Welcome.html)+- `amazonka-sagemaker-edge`: Manage and monitor ML models across fleets of smart devices. [Overview](https://aws.amazon.com/sagemaker/edge-manager/)+- `amazonka-sagemaker-featurestore-runtime`: A fully managed repository for machine learning features. [Overview](https://aws.amazon.com/sagemaker/feature-store/)+- `amazonka-savingsplans`: Flexible pricing model for AWS Services. [Overview](https://aws.amazon.com/savingsplans/)+- `amazonka-schemas`: Collect and organize schemas so that your schemas are in logical groups. [Overview](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-schema.html)+- `amazonka-securityhub`: Automate AWS security checks and centralize security alerts. [Overview](https://aws.amazon.com/security-hub/)+- `amazonka-service-quotas`: View and manage your quotas. [Overview](https://docs.aws.amazon.com/servicequotas/2019-06-24/apireference/Welcome.html)+- `amazonka-servicecatalog-appregistry`: Create a repository of your applications and associated resources. [Overview](https://docs.aws.amazon.com/servicecatalog/latest/adminguide/appregistry.html)+- `amazonka-signer`: Managed code-signing service to ensure the trust and integrity of your code. [Overview](https://docs.aws.amazon.com/signer/latest/developerguide/Welcome.html)+- `amazonka-sms-voice`:+- `amazonka-snow-device-management`: [Overview](https://docs.aws.amazon.com/snowball/latest/api-reference/API_Operations_AWS_Snow_Device_Management.html)+- `amazonka-ssm-contacts`: Systems Manager Incident Manager Contacts. [Overview](https://docs.aws.amazon.com/incident-manager/latest/APIReference/API_Operations_AWS_Systems_Manager_Incident_Manager_Contacts.html)+- `amazonka-ssm-incidents`: Incident management console to help users mitigate and recover from incidents. [Overview](https://docs.aws.amazon.com/incident-manager/latest/userguide/what-is-incident-manager.html)+- `amazonka-sso-admin`: [Overview](https://docs.aws.amazon.com/singlesignon/latest/APIReference/welcome.html)+- `amazonka-sso-oidc`: AWS Single Sign-On OpenID Connect. [Overview](https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html)+- `amazonka-sso`: Single Sign-On Portal. Centrally manage access to multiple AWS accounts or applications. [Overview](https://aws.amazon.com/single-sign-on/)+- `amazonka-synthetics`: Amazon CloudWatch Synthetics --- create canaries, configurable scripts that run on a schedule, to monitor your endpoints and APIs. [Overview](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries.html)+- `amazonka-transfer`: Simple, secure, and scalable file transfers. [Overview](https://aws.amazon.com/aws-transfer-family/)+- `amazonka-voice-id`: Real-time caller authentication and fraud risk detection using ML-powered voice analysis. [Overview](https://aws.amazon.com/connect/voice-id/)+- `amazonka-wellarchitected`: Programmatic access to the AWS Well-Architected Tool. [Overview](https://docs.aws.amazon.com/wellarchitected/latest/APIReference/Welcome.html)+- `amazonka-wisdom`: Deliver agents the information they need to solve issues in real-time. [Overview](https://aws.amazon.com/connect/wisdom/)+- `amazonka-worklink`: Provide secure mobile access to internal websites and web apps. [Overview](https://aws.amazon.com/worklink/)+- `amazonka-workmailmessageflow`: [Overview](https://docs.aws.amazon.com/workmail/latest/APIReference/API_Operations_Amazon_WorkMail_Message_Flow.html)++## [1.6.1](https://github.com/brendanhay/amazonka/tree/1.6.1)+Released: **03 Feb, 2019**, Compare: [1.6.0](https://github.com/brendanhay/amazonka/compare/1.6.0...1.6.1)++### Fixed++- Correctly catch exceptions in perform. [\#464](https://github.com/brendanhay/amazonka/pull/464)++### Changed++- Add a `MonadUnliftIO` instance for `AWST'`. [\#461](https://github.com/brendanhay/amazonka/pull/461)+- Add FromText instances for Int64, String and Seconds. [\#489](https://github.com/brendanhay/amazonka/pull/489)+- Add generalBracket for MonadMask instance on AWST'. [\#492](https://github.com/brendanhay/amazonka/pull/492)+- Remove fractional seconds from serialization of iso8601 timestamps [\#502](https://github.com/brendanhay/amazonka/pull/502)+++## [1.6.0](https://github.com/brendanhay/amazonka/tree/1.6.0)+Released: **16 May, 2018**, Compare: [1.5.0](https://github.com/brendanhay/amazonka/compare/1.5.0...1.6.0)++### Fixed++- GHC 8.4 compatibility. [\#456](https://github.com/brendanhay/amazonka/pull/456)+- Conduit `1.3` compatibility. [\#449](https://github.com/brendanhay/amazonka/pull/449)+- S3 `BucketName` now has a `FromJSON` instance. [\#452](https://github.com/brendanhay/amazonka/pull/452)+- S3 `ListObjectsV2` is now named correctly. [\#447](https://github.com/brendanhay/amazonka/pull/447)+- HTTP `Expect` headers are now stripped when presigning URLs. [\#444](https://github.com/brendanhay/amazonka/pull/444)+- Duplicate generated files no longer exist on case-insensitive file systems. [\#429](https://github.com/brendanhay/amazonka/pull/429), [\#655](https://github.com/brendanhay/amazonka/pull/655)+- EC2 metadata's instance identity document now has the correct(er) field types. [\#428](https://github.com/brendanhay/amazonka/pull/428)+- OpsWorks `DescribeApps` and `DescribeStacks` now correctly handle optional attribute values. [\#436](https://github.com/brendanhay/amazonka/pull/436), [\#438](https://github.com/brendanhay/amazonka/pull/438)++### Breaking Changes++- Lambda and other `rest-json` services with binary response payloads now return a raw `ByteString` instead of `HashMap Text Value`,+  fixing an issue where an empty body could not be deserialized. [\#428](https://github.com/brendanhay/amazonka/pull/394), [\#428](https://github.com/brendanhay/amazonka/pull/407)++### New Libraries++- `amazonka-alexa-business`: Alexa for Business SDK. [Overview](https://aws.amazon.com/alexaforbusiness/)+- `amazonka-appsync`: Automatically update data in web and mobile applications in real time, and updates data for offline users as soon as they reconnect. [Overview](https://aws.amazon.com/appsync/)+- `amazonka-autoscaling-plans`: Create instructions to configure dynamic scaling for the scalable resources in your application. [Overview](https://aws.amazon.com/autoscaling/)+- `amazonka-certificatemanager-pca`: Create a secure private certificate authority (CA). [Overview](https://docs.aws.amazon.com/acm-pca/latest/userguide/PcaWelcome.html)+- `amazonka-cloud9`: A cloud IDE for writing, running, and debugging code. [Overview](https://aws.amazon.com/cloud9/)+- `amazonka-comprehend`: Natural language processing (NLP) service that uses machine learning to find insights and relationships in text. [Overview](https://aws.amazon.com/comprehend/)+- `amazonka-connect`: Simple to use, cloud-based contact center. [Overview](https://aws.amazon.com/connect/)+- `amazonka-cost-explorer`: Dive deeper into your cost and usage data to identify trends, pinpoint cost drivers, and detect anomalies. [Overview](https://aws.amazon.com/aws-cost-management/aws-cost-explorer/)+- `amazonka-fms`: Centrally configure and manage firewall rules across accounts and applications. [Overview](https://aws.amazon.com/firewall-manager/)+- `amazonka-guardduty`: Intelligent threat detection and continuous monitoring to protect your AWS accounts and workloads. [Overview](https://aws.amazon.com/guardduty/)+- `amazonka-iot-analytics`: Analytics for IoT devices. [Overview](https://aws.amazon.com/iot-analytics/)+- `amazonka-iot-jobs-dataplane`: Define a set of remote operations that are sent to and executed on one or more devices connected to AWS IoT. [Overview](https://docs.aws.amazon.com/iot/latest/developerguide/iot-jobs.html)+- `amazonka-kinesis-video`: Capture, process, and store video streams for analytics and machine learning. [Overview](https://aws.amazon.com/kinesis/video-streams/)+- `amazonka-kinesis-video-media`: Media support for Kinesis Video. [Overview](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_Operations_Amazon_Kinesis_Video_Streams_Media.html)+- `amazonka-kinesis-video-archived-media`: Archived media support for Kinesis Video. [Overview](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_Operations_Amazon_Kinesis_Video_Streams_Archived_Media.html)+- `amazonka-mediaconvert`: Process video files and clips to prepare on-demand content for distribution or archiving. [Overview](https://aws.amazon.com/mediaconvert/)+- `amazonka-medialive`: Encode live video for broadcast and streaming to any device. [Overview](https://aws.amazon.com/medialive/)+- `amazonka-mediapackage`: Easily prepare and protect video for delivery to Internet devices. [Overview](https://aws.amazon.com/mediapackage/)+- `amazonka-mediastore`: Store and deliver video assets for live streaming media workflows. [Overview](https://aws.amazon.com/mediastore/)+- `amazonka-mediastore-dataplane`: MediaStore data plane. [Overview](https://docs.aws.amazon.com/mediastore/latest/apireference/API_Operations_AWS_Elemental_MediaStore_Data_Plane.html)+- `amazonka-mq`: Managed message broker service for Apache ActiveMQ. [Overview](https://aws.amazon.com/amazon-mq/)+- `amazonka-resourcegroups`: Resource groups make it easier to manage and automate tasks on large numbers of resources at one time. [Overview](https://docs.aws.amazon.com/ARG/latest/userguide/welcome.html)+- `amazonka-route53-autonaming`: Auto naming makes it easier to provision instances for microservices by automating DNS configuration. [Overview](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/autonaming.html)+- `amazonka-sagemaker`: Build, train, and deploy machine learning models at scale. [Overview](https://aws.amazon.com/sagemaker/)+- `amazonka-sagemaker-runtime`: Get inferences from SageMaker models. [Overview](https://docs.aws.amazon.com/sagemaker/latest/dg/API_Operations_Amazon_SageMaker_Runtime.html)+- `amazonka-secretsmanager`: Easily rotate, manage, and retrieve database credentials, API keys, and other secrets through their lifecycle. [Overview](https://aws.amazon.com/secrets-manager/)+- `amazonka-serverlessrepo`: Discover, deploy, and publish serverless applications. [Overview](https://aws.amazon.com/serverless/serverlessrepo/)+- `amazonka-transcribe`: Automatic speech recognition. [Overview](https://aws.amazon.com/transcribe/)+- `amazonka-translate`: A neural machine translation service that delivers fast, high-quality, and affordable language translation. [Overview](https://aws.amazon.com/translate/)+- `amazonka-workmail`: Secure, managed business email and calendar service with support for existing desktop and mobile email client applications. [Overview](https://aws.amazon.com/workfmail/)++### Updated Service Definitions++> All service definitions and services have been updated and regenerated.+Please see each individual library's commits for a list of changes.+++## [1.5.0](https://github.com/brendanhay/amazonka/tree/1.5.0)+Released: **15 November, 2017**, Compare: [1.4.5](https://github.com/brendanhay/amazonka/compare/1.4.5...1.5.0)++### Fixed++- V4 Signing Metadata is now correctly calculated for chunked request bodies. [\#403](https://github.com/brendanhay/amazonka/pull/403)+- DynamoDB Query/Scan pagination will correctly return all available items. [\#392](https://github.com/brendanhay/amazonka/pull/392)+- S3 `ReplicationStatus` is now parsed correctly. [\#372](https://github.com/brendanhay/amazonka/pull/372)+- OpsWorks `LayerAttributes` now correctly returns `Maybe` for `Map` values. [\#398](https://github.com/brendanhay/amazonka/pull/398)+- `newLogger` now (correctly) does not set binary mode for any passed handle. [\#381](https://github.com/brendanhay/amazonka/pull/381)+- Improved support for handling S3's `list-type=2` query strings. [\#391](https://github.com/brendanhay/amazonka/pull/391)+- Cabal files now have their `license-field` changed from `OtherLicense` to the correct `MPL-2.0`.++### Added++- Add AWS Signer for V2 Header Authentication. [\#383](https://github.com/brendanhay/amazonka/pull/383)+- Add support for ECS credentials discovery via the ECS container agent. [\#388](https://github.com/brendanhay/amazonka/pull/388)+- Add new regions `Montreal` (ca-central-1) and `London` (eu-west-2). [\#367](https://github.com/brendanhay/amazonka/pull/367)+- Add `hashedFileRange` and `chunkedFileRange` for preparing request bodies from file ranges. [\#359](https://github.com/brendanhay/amazonka/pull/359)++### New Libraries++- `amazonka-mobile`: Add and configure features for mobile apps, including authentication, data storage, backend logic, push notifications, content delivery, and analytics. [Overview](https://aws.amazon.com/mobile)+- `amazonka-pricing`: Price lists, pricing details, and pricing overview. [Overview](https://aws.amazon.com/pricing)+- `amazonka-athena`: An interactive query service that makes it easy to analyze data in Amazon S3 using standard SQL. [Overview](https://aws.amazon.com/athena)+- `amazonka-cloudhsmv2`: The newest (incompatible) API of AWS CloudHSM. [Overview](https://aws.amazon.com/cloudhsmv2)+- `amazonka-codestar`: Use a variety of project templates to start developing applications on Amazon EC2, AWS Lambda, and AWS Elastic Beanstalk. [Overview](https://aws.amazon.com/codestar)+- `amazonka-dynamodb-dax`: DynamoDB Accelerator (DAX) is a fully managed, highly available, in-memory cache for DynamoDB that delivers up to a 10x performance improvement. [Overview](https://aws.amazon.com/dynamodb/dax)+- `amazonka-glue`: A fully managed extract, transform, and load (ETL) service that makes it easy for customers to prepare and load their data for analytics. [Overview](https://aws.amazon.com/glue)+- `amazonka-greengrass`: Run local compute, messaging, data caching, and sync capabilities for connected devices in a secure way. [Overview](https://aws.amazon.com/greengrass)+- `amazonka-lex-runtime`: Build applications using a speech or text interface powered by the same technology that powers Amazon Alexa. [Overview](https://aws.amazon.com/lex)+- `amazonka-lex-models`: Build applications using a speech or text interface powered by the same technology that powers Amazon Alexa. [Overview](https://aws.amazon.com/lex)+- `amazonka-marketplace-entitlement`: Markplace entitlements service. [Overview](https://aws.amazon.com/marketplace)+- `amazonka-resourcegroupstagging`: Group and tag AWS resources. [Overview](https://docs.aws.amazon.com/resourcegroupstagging)++### Updated Service Definitions++> All service definitions and services have been updated and regenerated.+Please see each individual library's commits for a list of changes.++ ## [1.4.5](https://github.com/brendanhay/amazonka/tree/1.4.5)-Released: **04 December, 2016**, Compare: [1.4.5](https://github.com/brendanhay/amazonka/compare/1.4.4...1.4.5)+Released: **04 December, 2016**, Compare: [1.4.4](https://github.com/brendanhay/amazonka/compare/1.4.4...1.4.5)  ### Fixed 
README.md view
@@ -11,6 +11,73 @@ the types supplied by the various `amazonka-*` service libraries.  +## Migrating from 1.6.1 to 2.0++`CHANGELOG.md` is extremely thorough, but these notes should get you started:++* Modules have been moved from `Network.AWS.*` to `Amazonka.*`. Perform a find/replace on your import statements, e.g.:++  ```sh+  perl -pi -e 's/Network\.AWS/Amazonka/g' `find . -type f -name '*.hs'`+  ```++* The `AWST` transformer from `Control.Monad.Trans.AWS` has been removed. Functions such as `send` now take an `Env` as their first argument. You can provide an `Env` directly, or use whatever transformer or effect system you prefer.++* The `Credentials` data type no longer exists. Credential discovery methods are now represented as functions of type `EnvNoAuth -> m Env`, and common ones are exported from `Amazonka.Auth`. In most cases you can downcase the first character of a former `Credentials` constructor and it will do the right thing:++   ```haskell+   -- 1.6.1+   env <- newEnv Discover++   -- 2.0+   env <- newEnv discover+   ```++   A full list of new credential providers and their 1.6.1 equivalents, if any, are listed under the "Major Changes" heading of the 2.0 RC 2 section of `CHANGELOG.md`.++* On Windows, the {credential,config} files are read from `%USERPROFILE%\.aws\{credentials,config}` to [match the AWS SDK](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/creds-file.html#creds-file-general-info).++* Many Amazonka functions now require `Typeable` instances on request/response types. If you write code which is polymorphic across requests and responses, you may need to add `Typeable a` and `Typeable (AWSResponse a)` constraints alongside each `AWSRequest a` constraint.++* Request/response data types have been simplified:++  - Data type smart constructors are prefixed with `new`. Example: `Network.AWS.S3.getObject` -> `Amazonka.S3.newGetObject`.+  - All generated types export their constructors, which are always the "primed" name of the base type. Example: `data GetObject = GetObject' { ... }`.+  - Records also export all their fields, which no longer have any prefix.+  - The recommended way to fill in additional record fields is to use a library such as [`generic-lens`](https://hackage.haskell.org/package/generic-lens) or [`optics`](https://hackage.haskell.org/package/optics), possibly with the `OverloadedLabels` extension:++    ```haskell+    -- 1.6.1+    import Network.AWS.S3+    let req = getObject "my-bucket" "/foo/bar.txt" & goVersionId ?~ "some-version"++    -- 2.0+    {-# LANGUAGE OverloadedLabels #-}+    import Amazonka.S3+    import Control.Lens ((?~))+    import Data.Generics.Labels ()+    let req = newGetObject "my-bucket" "/foo/bar.txt" & #versionId ?~ "some-version"+    ```+  - Generated lenses are still available, but no longer use heuristic abbreviations. Example: `Network.AWS.S3.goVersionId` is now `Amazonka.S3.Lens.getObject_versionId`+  - Enums (sum types) are now `newtype` wrappers over `Text`. "Constructors" for these enums are provided as ["bundled" pattern synonyms](https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/pattern_synonyms.html#import-and-export-of-pattern-synonyms), but other values are permitted. This is especially useful for new EC2 instance types or new AWS region names. As with generated lens names, the type name is baked into the pattern synonym. Example: `InstanceType_R4_8xlarge`.++* All hand-written records in `amazonka-core` and `amazonka` now follow the conventions set by generated records: no leading underscores and no inconsistent prefixing of fields. As part of this, some functions were renamed or removed:++  - `Amazonka.Env.configure` -> `Amazonka.Env.configureService` (and its re-export from `Amazonka`)+  - `Amazonka.Env.override` -> `Amazonka.Env.overrideService` (and its re-export from `Amazonka`)+  - `Amazonka.Env.timeout` -> `Amazonka.Env.globalTimeout` (and its re-export from `Amazonka`)+  - `Amazonka.Env.within`: removed; with `AWST` gone, it is just a record update++  The removal of `AWST` means that `Network.AWS.Env` functions which used to operate on an `Env` inside a `MonadReader` now operate on the `Env` directly.++* Serialisation classes like `ToText` and `ToByteString`, and their associated helper functions, are no longer directly exported from module `Amazonka`. If you need these, you may need to import `Amazonka.Data` directly.++* The interface to the EC2 Instance Metadata Service (IMDS) is no longer exported from the root `Amazonka` module. If you used this, you should should import `Amazonka.EC2.Metadata` directly.++  - The functions `Amazonka.dynamic`, `Amazonka.metadata` and `Amazonka.userdata` have been removed in favour of their equivalents in `Amazonka.EC2.Metadata` which only require a HTTP `Manager`, not an entire `Env`.+  - If you were using them, read the `manager :: Manager` field directly from your `Env`.++ ## Contribute  For any problems, comments, or feedback please create an issue [here on GitHub](https://github.com/brendanhay/amazonka/issues).
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
amazonka.cabal view
@@ -1,92 +1,123 @@-name:                  amazonka-version:               1.4.5-synopsis:              Comprehensive Amazon Web Services SDK.-homepage:              https://github.com/brendanhay/amazonka-bug-reports:           https://github.com/brendanhay/amazonka/issues-license:               OtherLicense-license-file:          LICENSE-author:                Brendan Hay-maintainer:            Brendan Hay <brendan.g.hay@gmail.com>-copyright:             Copyright (c) 2013-2016 Brendan Hay-category:              Network, AWS, Cloud, Distributed Computing-build-type:            Simple-extra-source-files:    README.md CHANGELOG.md-cabal-version:         >= 1.10+cabal-version:   2.2+name:            amazonka+version:         2.0+synopsis:        Comprehensive Amazon Web Services SDK.+homepage:        https://github.com/brendanhay/amazonka+bug-reports:     https://github.com/brendanhay/amazonka/issues+license:         MPL-2.0+license-file:    LICENSE+author:          Brendan Hay+maintainer:+  Brendan Hay <brendan.g.hay+amazonka@gmail.com>, Jack Kelly <jack@jackkelly.name> +copyright:       Copyright (c) 2013-2023 Brendan Hay+category:        AWS+build-type:      Simple+extra-doc-files:+  CHANGELOG.md+  README.md+ description:-    This client library contains request and response logic to communicate-    with Amazon Web Service compatible APIs using the types supplied by the-    various @amazonka-*@ service libraries. See the <http://hackage.haskell.org/packages/#cat:AWS AWS>-    category on Hackage for supported services.-    .-    To get started, import the desired @amazonka-*@ library (such as-    <http://hackage.haskell.org/package/amazonka-ml/docs/Network-AWS-MachineLearning.html Network.AWS.MachineLearning>)-    and one of the following:-    .-    * "Control.Monad.Trans.AWS": The 'AWST' transformer and generalised operations.-    .-    * "Network.AWS": The 'AWS' monad and 'MonadAWS' type class for automatically-    lifting operations when embedded as a layer in a transformer stack.-    .-    GHC 7.8.4 and higher is officially supported.+  This client library contains request and response logic to communicate+  with Amazon Web Service compatible APIs using the types supplied by the+  various @amazonka-*@ service libraries. See the <http://hackage.haskell.org/packages/#cat:AWS AWS>+  category on Hackage for supported services.+  .+  To get started, import "Amazonka" and the desired @amazonka-*@ library (such as+  <http://hackage.haskell.org/package/amazonka-ml/docs/Network-AWS-MachineLearning.html Amazonka.MachineLearning>)+  .+  GHC 8.10.7 and higher is officially supported.  source-repository head-    type:     git-    location: git://github.com/brendanhay/amazonka.git--library-    default-language:  Haskell2010-    hs-source-dirs:    src--    ghc-options:       -Wall--    exposed-modules:-          Control.Monad.Trans.AWS-        , Network.AWS-        , Network.AWS.Auth-        , Network.AWS.Data-        , Network.AWS.EC2.Metadata-        , Network.AWS.Env-        , Network.AWS.Presign+  type:     git+  location: git://github.com/brendanhay/amazonka.git+  subdir:   lib/amazonka -    other-modules:-          Network.AWS.Internal.Body-        , Network.AWS.Internal.HTTP-        , Network.AWS.Internal.Logger+common base+  default-language:   Haskell2010+  ghc-options:+    -Wall -funbox-strict-fields -fwarn-incomplete-uni-patterns+    -fwarn-incomplete-record-updates -fwarn-missing-deriving-strategies+    -fwarn-unused-packages -    build-depends:-          amazonka-core       == 1.4.5.*-        , base                >= 4.7 && < 5-        , bytestring          >= 0.9-        , conduit             >= 1.1-        , conduit-extra       >= 1.1-        , directory           >= 1.2-        , exceptions          >= 0.6-        , http-conduit        >= 2.2 && < 3-        , ini                 >= 0.3.5-        , mmorph              >= 1-        , monad-control       >= 1-        , mtl                 >= 2.1.3.1-        , resourcet           >= 1.1-        , retry               >= 0.7-        , text                >= 1.1-        , time                >= 1.2-        , transformers        >= 0.2-        , transformers-base   >= 0.4-        , transformers-compat >= 0.3+  default-extensions:+    NoImplicitPrelude+    ConstraintKinds+    DataKinds+    DefaultSignatures+    DeriveAnyClass+    DeriveFoldable+    DeriveFunctor+    DeriveGeneric+    DeriveTraversable+    DerivingStrategies+    DerivingVia+    DuplicateRecordFields+    FlexibleContexts+    FlexibleInstances+    GADTs+    GeneralizedNewtypeDeriving+    LambdaCase+    NamedFieldPuns+    OverloadedStrings+    PackageImports+    PatternSynonyms+    RankNTypes+    RecordWildCards+    ScopedTypeVariables+    StandaloneDeriving+    StrictData+    TupleSections+    TypeApplications+    TypeFamilies+    ViewPatterns -test-suite tests-    type:              exitcode-stdio-1.0-    default-language:  Haskell2010-    hs-source-dirs:    test-    main-is:           Main.hs+  build-depends:      base >=4.12 && <5 -    ghc-options:       -Wall -threaded+library+  import:             base+  hs-source-dirs:     src+  exposed-modules:+    Amazonka+    Amazonka.Auth+    Amazonka.Auth.Background+    Amazonka.Auth.ConfigFile+    Amazonka.Auth.Container+    Amazonka.Auth.Exception+    Amazonka.Auth.InstanceProfile+    Amazonka.Auth.Keys+    Amazonka.Auth.SSO+    Amazonka.Auth.STS+    Amazonka.EC2.Metadata+    Amazonka.Env+    Amazonka.Env.Hooks+    Amazonka.HTTP+    Amazonka.Lens+    Amazonka.Logger+    Amazonka.Presign+    Amazonka.Send -    other-modules:+  reexported-modules:+    Amazonka.Data, Amazonka.Types, Amazonka.Bytes, Amazonka.Endpoint, Amazonka.Crypto -    build-depends:-          amazonka-        , base-        , tasty-        , tasty-hunit+  build-depends:+    , aeson                 ^>=1.5.0.0  || >=2.0 && <2.2 || ^>=2.2+    , amazonka-core         ^>=2.0+    , amazonka-sso          ^>=2.0+    , amazonka-sts          ^>=2.0+    , bytestring            >=0.10.8+    , conduit               >=1.3+    , directory             >=1.2+    , exceptions            ^>=0.10.4+    , http-client           >=0.5       && <0.8+    , http-conduit          >=2.3       && <3+    , http-types            >=0.12+    , ini                   >=0.3.5+    , lens                  >=4+    , resourcet             >=1.1+    , retry                 >=0.7.6.2+    , text                  >=1.1+    , time                  >=1.9+    , transformers          >=0.2+    , unordered-containers  ^>=0.2.14.0+    , uuid                  >=1.2.6     && <1.4
+ src/Amazonka.hs view
@@ -0,0 +1,445 @@+{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}++-- |+-- Module      : Amazonka+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- This module provides simple 'Env' and 'IO'-based operations which+-- can be performed against remote Amazon Web Services APIs, for use with the types+-- supplied by the various @amazonka-*@ libraries.+module Amazonka+  ( -- * Usage+    -- $usage++    -- * Authentication and Environment+    Env.Env,+    Env.EnvNoAuth,+    Env.Env' (..),+    Env.newEnv,+    Env.newEnvFromManager,+    Env.newEnvNoAuth,+    Env.newEnvNoAuthFromManager,+    Env.authMaybe,++    -- ** Service Configuration+    -- $service+    Env.overrideService,+    Env.configureService,+    Env.globalTimeout,+    Env.once,++    -- ** Running AWS Actions+    runResourceT,++    -- ** Credential Discovery+    -- $discovery+    AccessKey (..),+    SecretKey (..),+    SessionToken (..),+    discover,++    -- ** Supported Regions+    Region (..),++    -- ** Service Endpoints+    Endpoint (..),+    Endpoint.setEndpoint,++    -- * Sending Requests+    -- $sending+    send,+    sendEither,++    -- ** Pagination+    -- $pagination+    paginate,+    paginateEither,++    -- ** Waiters+    -- $waiters+    await,+    awaitEither,++    -- ** Unsigned+    sendUnsigned,+    sendUnsignedEither,++    -- ** Streaming+    -- $streaming+    ToBody (..),+    RequestBody (..),+    ResponseBody (..),++    -- *** Hashed Request Bodies+    ToHashedBody (..),+    HashedBody (..),+    Body.hashedFile,+    Body.hashedFileRange,+    Body.hashedBody,++    -- *** Chunked Request Bodies+    ChunkedBody (..),+    ChunkSize (..),+    defaultChunkSize,+    Body.chunkedFile,+    Body.chunkedFileRange,+    Body.unsafeChunkedBody,++    -- *** Response Bodies+    Body.sinkBody,++    -- *** File Size and MD5/SHA256+    Body.getFileSize,+    Crypto.sinkMD5,+    Crypto.sinkSHA256,++    -- * Presigning Requests+    -- $presigning+    presignURL,+    presign,++    -- * Running Asynchronous Actions+    -- $async++    -- * Handling Errors+    -- $errors+    AsError (..),+    AsAuthError (..),+    Lens.trying,+    Lens.catching,++    -- ** Building Error Prisms+    Error._MatchServiceError,+    Error.hasService,+    Error.hasStatus,+    Error.hasCode,++    -- * Logging+    -- $logging+    LogLevel (..),+    Logger,++    -- ** Constructing a Logger+    newLogger,++    -- * Re-exported Types+    module Amazonka.Core,+  )+where++import Amazonka.Auth+import Amazonka.Core hiding (presign)+import qualified Amazonka.Core.Lens.Internal as Lens+import qualified Amazonka.Crypto as Crypto+import qualified Amazonka.Data.Body as Body+import qualified Amazonka.Endpoint as Endpoint+import qualified Amazonka.Env as Env+import qualified Amazonka.Error as Error+import Amazonka.Logger+import Amazonka.Prelude+import qualified Amazonka.Presign as Presign+import Amazonka.Request (clientRequestURL)+import Amazonka.Send+  ( await,+    awaitEither,+    paginate,+    paginateEither,+    send,+    sendEither,+    sendUnsigned,+    sendUnsignedEither,+  )+import Control.Monad.Trans.Resource (runResourceT)++-- $usage+-- The key functions dealing with the request/response lifecycle are:+--+-- * 'send', 'sendEither'+--+-- * 'paginate', 'paginateEither'+--+-- * 'await', 'awaitEither'+--+-- These functions have constraints that types from the @amazonka-*@ libraries+-- satisfy. To utilise these, you will need to specify what 'Region' you wish to+-- operate in and your Amazon credentials for AuthN/AuthZ purposes.+--+-- Credentials can be supplied in a number of ways. Either via explicit keys,+-- via session profiles, or have Amazonka retrieve the credentials from an+-- underlying IAM Role/Profile.+--+-- As a basic example, you might wish to store an object in an S3 bucket using+-- <http://hackage.haskell.org/package/amazonka-s3 amazonka-s3>:+--+-- @+-- {-# LANGUAGE OverloadedStrings #-}+--+-- import qualified Amazonka as AWS+-- import qualified Amazonka.S3 as S3+-- import qualified System.IO as IO+--+-- example :: IO S3.PutObjectResponse+-- example = do+--     -- A new 'Logger' to replace the default noop logger is created, with the logger+--     -- set to print debug information and errors to stdout:+--     logger <- AWS.'Amazonka.newLogger' AWS.'Amazonka.Debug' IO.stdout+--+--     -- To specify configuration preferences, 'Amazonka.newEnv' is used to create a new+--     -- configuration environment. The argument to 'Amazonka.newEnv' is used to specify the+--     -- mechanism for supplying or retrieving AuthN/AuthZ information.+--     -- In this case 'Amazonka.discover' will cause the library to try a number of options such+--     -- as default environment variables, or an instance's IAM Profile and identity document:+--     discoveredEnv <- AWS.'Amazonka.newEnv' AWS.'Amazonka.discover'+--+--     let env =+--             discoveredEnv+--                 { AWS.logger = logger+--                 , AWS.region = AWS.'Amazonka.Frankfurt'+--                 }+--+--     -- The payload (and hash) for the S3 object is retrieved from a 'FilePath',+--     -- either 'hashedFile' or 'chunkedFile' can be used, with the latter ensuring+--     -- the contents of the file is enumerated exactly once, during send:+--     body <- AWS.chunkedFile AWS.defaultChunkSize "local\/path\/to\/object-payload"+--+--     -- We now run the 'AWS' computation with the overriden logger, performing the+--     -- 'PutObject' request.+--     AWS.runResourceT $+--         AWS.'Amazonka.send' env (S3.newPutObject "bucket-name" "object-key" body)+-- @++-- $discovery AuthN/AuthZ information is handled similarly to other AWS SDKs. You can read some of+-- the options available <http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs here>.+--+-- 'Amazonka.Auth.discover' should be your default way of requesting credentials, as it searches the+-- standard places that the official AWS SDKs use.+--+-- Authentication methods which return short-lived credentials (e.g., when running on+-- an EC2 instance) fork a background thread which transparently handles the expiry+-- and subsequent refresh of IAM profile information. See+-- 'Amazonka.Auth.Background.fetchAuthInBackground' for more information.+--+-- /See:/ "Amazonka.Auth", if you want to commit to specific authentication methods.+--+-- /See:/ 'Amazonka.Auth.runCredentialChain' if you want to build your own credential chain.++-- $sending+-- To send a request you need to create a value of the desired operation type using+-- the relevant constructor, as well as any further modifications of default/optional+-- parameters using the appropriate lenses. This value can then be sent using 'send'+-- or 'paginate' and the library will take care of serialisation/authentication and+-- so forth.+--+-- The default 'Service' configuration for a request contains retry configuration that is used to+-- determine if a request can safely be retried and what kind of back off/on strategy+-- should be used. (Usually exponential.)+-- Typically services define retry strategies that handle throttling, general server+-- errors and transport errors. Streaming requests are never retried.++-- $pagination+-- Some AWS operations return results that are incomplete and require subsequent+-- requests in order to obtain the entire result set. The process of sending+-- subsequent requests to continue where a previous request left off is called+-- pagination. For example, the 'ListObjects' operation of Amazon S3 returns up to+-- 1000 objects at a time, and you must send subsequent requests with the+-- appropriate Marker in order to retrieve the next page of results.+--+-- Operations that have an 'AWSPager' instance can transparently perform subsequent+-- requests, correctly setting markers and other request facets to iterate through+-- the entire result set of a truncated API operation. Operations which support+-- this have an additional note in the documentation.+--+-- Many operations have the ability to filter results on the server side. See the+-- individual operation parameters for details.++-- $waiters+-- Waiters poll by repeatedly sending a request until some remote success condition+-- configured by the 'Wait' specification is fulfilled. The 'Wait' specification+-- determines how many attempts should be made, in addition to delay and retry strategies.+-- Error conditions that are not handled by the 'Wait' configuration will be thrown,+-- or the first successful response that fulfills the success condition will be+-- returned.+--+-- 'Wait' specifications can be found under the @Amazonka.{ServiceName}.Waiters@+-- namespace for services which support 'await'.++-- $service+-- When a request is sent, various values such as the endpoint,+-- retry strategy, timeout and error handlers are taken from the associated 'Service'+-- for a request. For example, 'DynamoDB' will use the 'Amazonka.DynamoDB.defaultService'+-- configuration when sending 'PutItem', 'Query' and all other operations.+--+-- You can modify a specific 'Service''s default configuration by using+-- 'Amazonka.Env.configureService'. To modify all configurations simultaneously, see+-- 'Amazonka.Env.overrideService'.+--+-- An example of how you might alter default configuration using these mechanisms+-- is demonstrated below. Firstly, the default 'dynamoDB' service is configured to+-- use non-SSL localhost as the endpoint:+--+-- @+-- import qualified Amazonka as AWS+-- import qualified Amazonka.DynamoDB as DynamoDB+--+-- let dynamo :: AWS.Service+--     dynamo = AWS.setEndpoint False "localhost" 8000 DynamoDB.defaultService+-- @+--+-- The updated configuration is then passed to the 'Env' during setup:+--+-- @+-- env <- AWS.'Amazonka.configureService' dynamo \<$\> AWS.'Amazonka.newEnv' AWS.'Amazonka.discover'+--+-- AWS.runResourceT $ do+--     -- This S3 operation will communicate with remote AWS APIs.+--     x <- AWS.send env newListBuckets+--+--     -- DynamoDB operations will communicate with localhost:8000.+--     y <- AWS.send env Dynamo.newListTables+--+--     -- Any operations for services other than DynamoDB, are not affected.+--     ...+-- @+--+-- You can also scope the service configuration modifications to specific actions:+--+-- @+-- env <- AWS.'Amazonka.newEnv' AWS.'Amazonka.discover'+--+-- AWS.runResourceT $ do+--     -- Service operations here will communicate with AWS, even remote DynamoDB.+--     x <- AWS.send env Dynamo.newListTables+--+--     -- Here DynamoDB operations will communicate with localhost:8000.+--     y <- AWS.send (AWS.configure dynamo env) Dynamo.newListTables+-- @+--+-- Functions such as 'Amazonka.once' and 'Amazonka.globalTimeout' can+-- also be used to modify service configuration for all (or specific)+-- requests.++-- $streaming+-- Streaming comes in two flavours. 'HashedBody' represents a request+-- that requires a precomputed 'SHA256' hash, or a 'ChunkedBody' type for those services+-- that can perform incremental signing and do not require the entire payload to+-- be hashed (such as S3). The type signatures for request smart constructors+-- advertise which respective body type is required, denoting the underlying signing+-- capabilities.+--+-- 'ToHashedBody' and 'ToBody' typeclass instances are available to construct the+-- streaming bodies, automatically calculating any hash or size as needed for types+-- such as 'Text', 'ByteString', or Aeson's 'Value' type. To read files and other+-- 'IO' primitives, functions such as 'hashedFile', 'chunkedFile', or 'hashedBody'+-- should be used.+--+-- For responses that contain streaming bodies (such as 'GetObject'), you can use+-- 'sinkBody' to connect the response body to a+-- <http://hackage.haskell.org/package/conduit conduit>-compatible sink.++-- $presigning+-- Presigning requires the 'Service' signer to be an instance of 'AWSPresigner'.+-- Not all signing algorithms support this.++-- $async+-- Requests can be sent asynchronously, but due to guarantees about resource closure+-- require the use of "UnliftIO.Async".+--+-- The following example demonstrates retrieving two objects from S3 concurrently:+--+-- @+-- {-# LANGUAGE OverloadedStrings #-}+-- import qualified Amazonka as AWS+-- import qualified Amazonka.S3 as S3+-- import qualified UnliftIO.Async as Async+--+-- let requestA = S3.newGetObject "bucket" "prefix/object-a"+-- let requestB = S3.newGetObject "bucket" "prefix/object-b"+--+-- runResourceT $+--   Async.'UnliftIO.Async.withAsync' (send env requestA) $ \\asyncA ->+--     Async.'UnliftIO.Async.withAsync' (send env requestB) $ \\asyncB -> do+--       Async.'UnliftIO.Async.waitBoth' asyncA asyncB+-- @+--+-- If you are running many async requests in parallel, using+-- 'Control.Monad.Trans.Cont.ContT' can hide the giant callback pyramid:+--+-- @+-- runResourceT . 'Control.Monad.Trans.Cont.evalContT' $ do+--   asyncA <- ContT $ Async.'UnliftIO.Async.withAsync' (send env requestA)+--   asyncB <- ContT $ Async.'UnliftIO.Async.withAsync' (send env requestB)+--   Async.'UnliftIO.Async.waitBoth' asyncA asyncB+-- @++-- $errors+-- Errors are either returned or thrown by the library using 'IO'. Sub-errors of+-- the canonical 'Error' type can be caught using 'trying' or 'catching' and the+-- appropriate 'AsError' 'Prism' when using the non-'Either' send variants:+--+-- @+-- trying '_Error'          (send $ newListObjects "bucket-name") :: Either 'Amazonka.Types.Error'          ListObjectsResponse+-- trying '_TransportError' (send $ newListObjects "bucket-name") :: Either 'HttpException'  ListObjectsResponse+-- trying '_SerializeError' (send $ newListObjects "bucket-name") :: Either 'Amazonka.Types.SerializeError' ListObjectsResponse+-- trying '_ServiceError'   (send $ newListObjects "bucket-name") :: Either 'Amazonka.Types.ServiceError'   ListObjectsResponse+-- @+--+-- Many of the individual @amazonka-*@ libraries export compatible 'Control.Lens.Fold's for+-- matching service specific error codes and messages in the style above.+-- See the @Error Matchers@ heading in each respective library for details.++-- $logging+-- The exposed logging interface is a primitive 'Logger' function which the+-- hooks system calls throughout the request/response process. This allows the+-- library to output useful information and diagnostics.+--+-- The 'newLogger' function can be used to construct a simple logger which writes+-- output to a 'Handle', but in most production code you should probably consider+-- using a more robust logging library such as+-- <http://hackage.haskell.org/package/tinylog tinylog> or+-- <http://hackage.haskell.org/package/fast-logger fast-logger>.++-- | Presign an URL that is valid from the specified time until the+-- number of seconds expiry has elapsed.+presignURL ::+  ( MonadIO m,+    AWSRequest a+  ) =>+  Env ->+  -- | Signing time.+  UTCTime ->+  -- | Expiry time.+  Seconds ->+  -- | Request to presign.+  a ->+  m ByteString+presignURL env time expires =+  fmap clientRequestURL+    . presign env time expires++-- | Presign an HTTP request that is valid from the specified time until the+-- number of seconds expiry has elapsed.+presign ::+  ( MonadIO m,+    AWSRequest a+  ) =>+  Env ->+  -- | Signing time.+  UTCTime ->+  -- | Expiry time.+  Seconds ->+  -- | Request to presign.+  a ->+  m ClientRequest+presign env time expires rq = withAuth (runIdentity $ Env.auth env) $ \ae ->+  pure $!+    Presign.presignWith+      (Env.overrides env)+      ae+      (Env.region env)+      time+      expires+      rq
+ src/Amazonka/Auth.hs view
@@ -0,0 +1,131 @@+-- |+-- Module      : Amazonka.Auth+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Explicitly specify your Amazon AWS security credentials, or retrieve them+-- from the underlying OS.+--+-- The format of environment variables and the credentials file follows the official+-- <http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs AWS SDK guidelines>.+module Amazonka.Auth+  ( -- * Authentication++    -- ** Retrieving Authentication+    Auth (..),+    withAuth,++    -- ** Automatically Fetching Credentials+    discover,++    -- ** Credential Providers+    runCredentialChain,+    fromKeys,+    fromSession,+    fromTemporarySession,+    fromKeysEnv,+    fromFilePath,+    fromFileEnv,+    fromContainer,+    fromContainerEnv,+    fromAssumedRole,+    fromWebIdentity,+    fromWebIdentityEnv,+    fromDefaultInstanceProfile,+    fromNamedInstanceProfile,+    fromSSO,++    -- ** Keys+    AccessKey (..),+    SecretKey (..),+    SessionToken (..),++    -- ** Handling Errors+    AsAuthError (..),+    AuthError (..),++    -- * Env'+    -- $env+    Env,+    EnvNoAuth,+    Env' (..),+  )+where++import Amazonka.Auth.ConfigFile (fromFileEnv, fromFilePath)+import Amazonka.Auth.Container (fromContainer, fromContainerEnv)+import Amazonka.Auth.Exception+import Amazonka.Auth.InstanceProfile (fromDefaultInstanceProfile, fromNamedInstanceProfile)+import Amazonka.Auth.Keys (fromKeys, fromKeysEnv, fromSession, fromTemporarySession)+import Amazonka.Auth.SSO (fromSSO)+import Amazonka.Auth.STS (fromAssumedRole, fromWebIdentity, fromWebIdentityEnv)+import Amazonka.Core.Lens.Internal (catching_)+import Amazonka.EC2.Metadata+import Amazonka.Env (Env, Env' (..), EnvNoAuth)+import Amazonka.Prelude+import Amazonka.Types+import Control.Monad.Catch (MonadCatch (..), throwM)++-- | Attempt to fetch credentials in a way similar to the official AWS+-- SDKs. The <https://github.com/aws/aws-sdk-cpp/blob/fb8cbebf2fd62720b65aeff841ad2950e73d8ebd/Docs/Credentials_Providers.md#default-credential-provider-chain C++ SDK>+-- lists the following sequence:+--+-- *   Check environment variables for keys provided directly+--     (@AWS_ACCESS_KEY_ID@, @AWS_SECRET_ACCESS_KEY@, optionally+--     @AWS_SESSION_TOKEN@)+--+-- *   Check credentials/config files for authentication information,+--     respecting the @AWS_PROFILE@ environment variable.+--+-- *   Exchange a Web Identity for AWS Credentials using+--     @sts:AssumeRoleWithWebIdentity@, respecting the+--     @AWS_WEB_IDENTITY_TOKEN_FILE@, @AWS_ROLE_ARN@, and optionally the+--     @AWS_ROLE_SESSION_NAME@ environment variables.+--+-- *   Retrieve credentials from the ECS Container Agent if the+--     @AWS_CONTAINER_CREDENTIALS_RELATIVE_URI@ environment variable is+--     set.+--+-- *   If we think we're running on EC2, retrieve the first available+--     IAM profile from the instance identity document, and use this to+--     set the 'Region'. We attempt to resolve <http://instance-data>+--     rather than directly retrieving <http://169.254.169.254> for IAM+--     profile information. This ensures that the DNS lookup terminates+--     promptly if not running on EC2, but means that your VPC must have+--     @enableDnsSupport@ and @enableDnsHostnames@ set.+--+--     __NOTE__: This is not 100% consistent with the AWS SDKs,+--     which does not attempt to query the ECS service if either+--     @AWS_CONTAINER_CREDENTIALS_RELATIVE_URI@ or+--     @AWS_CONTAINER_CREDENTIALS_FULL_URI@ are set.+--+--     /See:/ https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/EC2ContainerCredentialsProviderWrapper.html+discover ::+  (MonadCatch m, MonadIO m, Foldable withAuth) =>+  Env' withAuth ->+  m Env+discover =+  runCredentialChain+    [ fromKeysEnv,+      fromFileEnv,+      fromWebIdentityEnv,+      fromContainerEnv,+      \env -> do+        onEC2 <- isEC2 $ manager env+        unless onEC2 $ throwM CredentialChainExhausted+        fromDefaultInstanceProfile env+    ]++-- | Compose a list of credential-providing functions by testing each+-- until one returns successfully. If they throw 'AuthError', the next+-- function in the chain will be tried. Throws+-- 'CredentialChainExhausted' if the list is exhausted.+runCredentialChain :: MonadCatch m => [a -> m b] -> a -> m b+runCredentialChain chain env =+  case chain of+    [] -> throwM CredentialChainExhausted+    provider : chain' ->+      catching_ _AuthError (provider env) $ runCredentialChain chain' env
+ src/Amazonka/Auth/Background.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE Strict #-}++-- |+-- Module      : Amazonka.Auth.Background+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Helpers for authentication schemes which refresh themselves in the+-- background.+module Amazonka.Auth.Background where++import Amazonka.Auth.Exception+import Amazonka.Data+import Amazonka.Prelude+import Amazonka.Types+import Control.Concurrent (ThreadId)+import qualified Control.Concurrent as Concurrent+import qualified Control.Exception as Exception+import Data.IORef (IORef)+import qualified Data.IORef as IORef+import qualified Data.Time as Time+import System.Mem.Weak (Weak)+import qualified System.Mem.Weak as Weak++-- | Implements the background fetching behavior used by (among others)+-- 'fromProfileName' and 'fromContainer'. Given an 'IO' action that produces an+-- 'AuthEnv', this spawns a thread that mutates the 'IORef' returned in the+-- resulting 'Auth' to keep the temporary credentials up to date.+fetchAuthInBackground :: IO AuthEnv -> IO Auth+fetchAuthInBackground menv =+  menv >>= \env -> liftIO $+    case expiration env of+      Nothing -> pure (Auth env)+      Just x -> do+        r <- IORef.newIORef env+        p <- Concurrent.myThreadId+        s <- timer menv r p x++        pure (Ref s r)+  where+    timer :: IO AuthEnv -> IORef AuthEnv -> ThreadId -> ISO8601 -> IO ThreadId+    timer ma r p x =+      Concurrent.forkIO $ do+        s <- Concurrent.myThreadId+        w <- IORef.mkWeakIORef r (Concurrent.killThread s)++        loop ma w p x++    loop :: IO AuthEnv -> Weak (IORef AuthEnv) -> ThreadId -> ISO8601 -> IO ()+    loop ma w p x = do+      untilExpiry <- diff x <$> Time.getCurrentTime+      -- Refresh the token within 5 minutes of expiry, or half its lifetime if+      -- sooner than that. This is to account for execution time of the refresh action.+      let fiveMinutes = 5 * 60 * 1000000+      Concurrent.threadDelay $+        if untilExpiry > fiveMinutes+          then untilExpiry - fiveMinutes+          else untilExpiry `div` 2++      env <- Exception.try ma+      case env of+        Left e -> Exception.throwTo p (RetrievalError e)+        Right a -> do+          mr <- Weak.deRefWeak w+          case mr of+            Nothing -> pure ()+            Just r -> do+              IORef.atomicWriteIORef r a+              maybe (pure ()) (loop ma w p) (expiration a)++    diff (Time x) y = picoToMicro $ if n > 0 then n else 1+      where+        n = truncate (Time.diffUTCTime x y) - 60+        picoToMicro = (* 1000000)
+ src/Amazonka/Auth/ConfigFile.hs view
@@ -0,0 +1,280 @@+-- |+-- Module      : Amazonka.Auth.ConfigFile+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Retrieve authentication credentials from AWS config/credentials files.+module Amazonka.Auth.ConfigFile where++import Amazonka.Auth.Container (fromContainerEnv)+import Amazonka.Auth.Exception+import Amazonka.Auth.InstanceProfile (fromDefaultInstanceProfile)+import Amazonka.Auth.Keys (fromKeysEnv)+import Amazonka.Auth.SSO (fromSSO, relativeCachedTokenFile)+import Amazonka.Auth.STS (fromAssumedRole, fromWebIdentity)+import Amazonka.Data+import Amazonka.Env (Env, Env' (..), lookupRegion)+import Amazonka.Prelude+import Amazonka.Types+import qualified Control.Exception as Exception+import Control.Exception.Lens (handling_, _IOException)+import Control.Monad.Trans.Reader (ReaderT, ask, runReaderT)+import Control.Monad.Trans.State (StateT, evalStateT, get, modify)+import Data.Foldable (asum)+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Ini as INI+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified System.Directory as Directory+import qualified System.Environment as Environment+import System.Info (os)++-- | Retrieve credentials from the AWS config/credentials files, as+-- Amazonka currently understands them:+--+-- * AWS recommends credentials do not live in the config file, but+--   allows it.+--+-- * Sections in the config file start should either be named+--   @[default]@ or @[profile foo]@. Unprefixed @[foo]@ currently+--   "happens to work" but is not officially supported, to match the+--   observed behaviour of the AWS SDK/CLI.+--+-- * Sections in the credentials file are always unprefixed -+--   @[default]@ or @[foo]@.+--+-- /See:/ the 'ConfigProfile' type, to understand the methods Amazonka+-- currently supports.+fromFilePath ::+  forall m withAuth.+  (MonadIO m, Foldable withAuth) =>+  -- | Profile name+  Text ->+  -- | Credentials file+  FilePath ->+  -- | Config file+  FilePath ->+  Env' withAuth ->+  m Env+fromFilePath profile credentialsFile configFile env = liftIO $ do+  credentialsIni <- loadIniFile credentialsFile+  -- If we fail to read the config file, assume it's empty and move+  -- on. It is valid to configure only a credentials file if you only+  -- want to set keys, for example.+  configIni <-+    Exception.catchJust+      (\(_ :: AuthError) -> Just mempty)+      (loadIniFile configFile)+      pure++  let config = mergeConfigs credentialsIni configIni+  env' <-+    evalConfig profile+      & (`runReaderT` config)+      & (`evalStateT` mempty)++  -- A number of settings in the AWS config files should be+  -- overridable by environment variables, but aren't. We make a point+  -- of at least respecting the AWS_REGION variable, but leave the+  -- rest to future work.+  --+  -- See: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html+  lookupRegion <&> \case+    Nothing -> env'+    Just region -> env' {region}+  where+    loadIniFile :: FilePath -> IO (HashMap Text [(Text, Text)])+    loadIniFile path = do+      exists <- Directory.doesFileExist path+      unless exists . Exception.throwIO $ MissingFileError path+      INI.readIniFile path >>= \case+        Left e ->+          Exception.throwIO . InvalidFileError . Text.pack $ path <> ": " <> e+        Right ini -> pure $ INI.iniSections ini++    -- Parse the matched config, and extract auth credentials from it,+    -- recursively if necessary.+    evalConfig ::+      Text ->+      ReaderT+        (HashMap Text (HashMap Text Text)) -- Map of profiles and their settings+        (StateT [Text] IO) -- List of source_profiles we've seen already+        Env+    evalConfig pName = do+      config <- ask+      case HashMap.lookup pName config of+        Nothing ->+          liftIO . Exception.throwIO . InvalidFileError $+            "Missing profile: " <> Text.pack (show pName)+        Just p -> case parseConfigProfile p of+          Nothing ->+            liftIO . Exception.throwIO . InvalidFileError $+              "Parse error in profile: " <> Text.pack (show pName)+          Just (cp, mRegion) -> do+            env' <- case cp of+              ExplicitKeys keys ->+                pure env {auth = Identity $ Auth keys}+              AssumeRoleFromProfile roleArn sourceProfileName -> do+                seenProfiles <- lift get+                if sourceProfileName `elem` seenProfiles+                  then+                    let trace = reverse seenProfiles ++ [last seenProfiles]+                        textTrace = Text.intercalate " -> " trace+                     in liftIO+                          . Exception.throwIO+                          . InvalidFileError+                          $ "Infinite source_profile loop: " <> textTrace+                  else do+                    lift . modify $ (sourceProfileName :)+                    sourceEnv <- evalConfig sourceProfileName+                    fromAssumedRole roleArn "amazonka-assumed-role" sourceEnv+              AssumeRoleFromCredentialSource roleArn source -> do+                sourceEnv <- case source of+                  Environment -> fromKeysEnv env+                  Ec2InstanceMetadata -> fromDefaultInstanceProfile env+                  EcsContainer -> fromContainerEnv env+                fromAssumedRole roleArn "amazonka-assumed-role" sourceEnv+              AssumeRoleWithWebIdentity roleArn mRoleSessionName tokenFile ->+                fromWebIdentity tokenFile roleArn mRoleSessionName env+              AssumeRoleViaSSO startUrl ssoRegion accountId roleName -> do+                cachedTokenFile <-+                  liftIO $+                    configPathRelative =<< relativeCachedTokenFile startUrl+                fromSSO cachedTokenFile ssoRegion accountId roleName env++            -- Once we have the env from the profile, apply the region+            -- if we parsed one out.+            pure $ case mRegion of+              Nothing -> env'+              Just region -> env' {region}++mergeConfigs ::+  -- | Credentials+  HashMap Text [(Text, Text)] ->+  -- | Config+  HashMap Text [(Text, Text)] ->+  HashMap Text (HashMap Text Text)+mergeConfigs creds confs =+  HashMap.unionWith+    HashMap.union+    (HashMap.fromList <$> creds)+    (HashMap.fromList <$> stripProfiles confs)+  where+    stripProfiles :: HashMap Text v -> HashMap Text v+    stripProfiles = HashMap.mapKeys $ Text.unwords . stripProfile . Text.words++    stripProfile = \case+      [w] -> [w]+      ("profile" : ws) -> ws+      ws -> ws++parseConfigProfile :: HashMap Text Text -> Maybe (ConfigProfile, Maybe Region)+parseConfigProfile profile = parseProfile <&> (,parseRegion)+  where+    parseProfile :: Maybe ConfigProfile+    parseProfile =+      asum+        [ explicitKey,+          assumeRoleFromProfile,+          assumeRoleFromCredentialSource,+          assumeRoleWithWebIdentity,+          assumeRoleViaSSO+        ]++    parseRegion :: Maybe Region+    parseRegion = Region' <$> HashMap.lookup "region" profile++    explicitKey =+      fmap ExplicitKeys $+        AuthEnv+          <$> ( AccessKey . Text.encodeUtf8+                  <$> HashMap.lookup "aws_access_key_id" profile+              )+          <*> ( Sensitive . SecretKey . Text.encodeUtf8+                  <$> HashMap.lookup "aws_secret_access_key" profile+              )+          <*> Just+            ( Sensitive . SessionToken . Text.encodeUtf8+                <$> HashMap.lookup "aws_session_token" profile+            )+          <*> Just Nothing -- No token expiry in config file+    assumeRoleFromProfile =+      AssumeRoleFromProfile+        <$> HashMap.lookup "role_arn" profile+        <*> HashMap.lookup "source_profile" profile++    assumeRoleFromCredentialSource =+      AssumeRoleFromCredentialSource+        <$> HashMap.lookup "role_arn" profile+        <*> ( HashMap.lookup "credential_source" profile >>= \case+                "Environment" -> Just Environment+                "Ec2InstanceMetadata" -> Just Ec2InstanceMetadata+                "EcsContainer" -> Just EcsContainer+                _ -> Nothing+            )++    assumeRoleWithWebIdentity =+      AssumeRoleWithWebIdentity+        <$> HashMap.lookup "role_arn" profile+        <*> Just (HashMap.lookup "role_session_name" profile)+        <*> (Text.unpack <$> HashMap.lookup "web_identity_token_file" profile)++    assumeRoleViaSSO =+      AssumeRoleViaSSO+        <$> HashMap.lookup "sso_start_url" profile+        <*> (Region' <$> HashMap.lookup "sso_region" profile)+        <*> HashMap.lookup "sso_account_id" profile+        <*> HashMap.lookup "sso_role_name" profile++data ConfigProfile+  = -- | Recognizes @aws_access_key_id@, @aws_secret_access_key@, and+    -- optionally @aws_session_token@.+    ExplicitKeys AuthEnv+  | -- | Recognizes @role_arn@ and @source_profile@.+    AssumeRoleFromProfile Text Text+  | -- | Recognizes @role_arn@ and @credential_source@.+    AssumeRoleFromCredentialSource Text CredentialSource+  | -- | Recognizes @role_arn@, @role_session_name@, and+    -- @web_identity_token_file@.+    AssumeRoleWithWebIdentity Text (Maybe Text) FilePath+  | -- | Recognizes @sso_start_url@, @sso_region@, @sso_account_id@, and+    -- @sso_role_name@.+    AssumeRoleViaSSO Text Region Text Text+  deriving stock (Eq, Show, Generic)++data CredentialSource = Environment | Ec2InstanceMetadata | EcsContainer+  deriving stock (Eq, Show, Generic)++-- | Loads the default config/credentials INI files and selects a+-- profile by environment variable (@AWS_PROFILE@).+--+-- Throws 'MissingFileError' if 'credFile' is missing, or 'InvalidFileError'+-- if an error occurs during parsing.+--+-- This looks in in the @HOME@ directory as determined by the+-- <http://hackage.haskell.org/package/directory directory> library.+--+-- * Not Windows: @$HOME\/.aws\/credentials@+--+-- * Windows: @%USERPROFILE%\\.aws\\credentials@+fromFileEnv ::+  (MonadIO m, Foldable withAuth) => Env' withAuth -> m Env+fromFileEnv env = liftIO $ do+  mProfile <- Environment.lookupEnv "AWS_PROFILE"+  cred <- configPathRelative "/.aws/credentials"+  conf <- configPathRelative "/.aws/config"++  fromFilePath (maybe "default" Text.pack mProfile) cred conf env++configPathRelative :: String -> IO String+configPathRelative p = handling_ _IOException err dir+  where+    err = Exception.throwIO $ MissingFileError ("$HOME" ++ p)+    dir = case os of+      "mingw32" ->+        Environment.lookupEnv "USERPROFILE"+          >>= maybe (Exception.throwIO $ MissingFileError "%USERPROFILE%") pure+      _ -> Directory.getHomeDirectory <&> (++ p)
+ src/Amazonka/Auth/Container.hs view
@@ -0,0 +1,81 @@+-- |+-- Module      : Amazonka.Auth+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Fetch credentials from a metadata service when running in an ECS+-- Container.+module Amazonka.Auth.Container where++import Amazonka.Auth.Background (fetchAuthInBackground)+import Amazonka.Auth.Exception+import Amazonka.Data+import Amazonka.Env (Env, Env' (..))+import Amazonka.Prelude+import Amazonka.Types+import qualified Control.Exception as Exception+import qualified Data.Text as Text+import qualified Network.HTTP.Client as Client+import qualified System.Environment as Environment++-- | Obtain credentials exposed to a task via the ECS container agent, as+-- described in the <http://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html IAM Roles for Tasks>+-- section of the AWS ECS documentation. The credentials are obtained by making+-- a request to the given URL.+--+-- The ECS container agent provides an access key, secret key, session token,+-- and expiration time. As these are temporary credentials, this function also+-- starts a refresh thread that will periodically fetch fresh credentials before+-- the current ones expire.+fromContainer ::+  MonadIO m =>+  -- | Absolute URL+  Text ->+  Env' withAuth ->+  m Env+fromContainer url env =+  liftIO $ do+    req <- Client.parseUrlThrow $ Text.unpack url+    keys <- fetchAuthInBackground (renew req)++    pure env {auth = Identity keys}+  where+    renew :: ClientRequest -> IO AuthEnv+    renew req = do+      rs <- Client.httpLbs req $ manager env++      either+        (Exception.throwIO . invalidIdentityErr)+        pure+        (eitherDecode (Client.responseBody rs))++    invalidIdentityErr =+      InvalidIAMError+        . mappend "Error parsing Task Identity Document "+        . Text.pack++-- | Obtain credentials from the ECS container agent, by querying+-- <http://169.254.170.2> at the path contained by the+-- @AWS_CONTAINER_CREDENTIALS_RELATIVE_URI@ environment variable.+--+-- Throws 'MissingEnvError' if the @AWS_CONTAINER_CREDENTIALS_RELATIVE_URI@+-- environment variable is not set or 'InvalidIAMError' if the payload returned+-- by the ECS container agent is not of the expected format.+--+-- __NOTE:__ We do not currently respect the+-- @AWS_CONTAINER_CREDENTIALS_FULL_URI@ or @AWS_CONTAINTER_AUTHORIZATION_TOKEN@+-- environment variable. If you need support for these, please file a PR.+fromContainerEnv ::+  MonadIO m =>+  Env' withAuth ->+  m Env+fromContainerEnv env = liftIO $ do+  uriRel <-+    Environment.lookupEnv "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"+      >>= maybe+        (Exception.throwIO $ MissingEnvError "Unable to read AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")+        pure+  fromContainer (Text.pack $ "http://169.254.170.2" <> uriRel) env
+ src/Amazonka/Auth/Exception.hs view
@@ -0,0 +1,90 @@+-- |+-- Module      : Amazonka.Auth.Exception+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Exception for errors involving AWS authentication.+module Amazonka.Auth.Exception where++import Amazonka.Core.Lens.Internal (exception, prism)+import Amazonka.Data+import Amazonka.Prelude+import Amazonka.Types++-- | An error thrown when attempting to read AuthN/AuthZ information.+data AuthError+  = RetrievalError HttpException+  | MissingEnvError Text+  | MissingFileError FilePath+  | InvalidFileError Text+  | InvalidIAMError Text+  | CredentialChainExhausted+  deriving stock (Show, Generic)++instance Exception AuthError++instance ToLog AuthError where+  build = \case+    RetrievalError e -> build e+    MissingEnvError e -> "[MissingEnvError]  { message = " <> build e <> "}"+    MissingFileError f -> "[MissingFileError] { path = " <> build f <> "}"+    InvalidFileError e -> "[InvalidFileError] { message = " <> build e <> "}"+    InvalidIAMError e -> "[InvalidIAMError]  { message = " <> build e <> "}"+    CredentialChainExhausted -> "[CredentialChainExhausted]"++class AsAuthError a where+  -- | A general authentication error.+  _AuthError :: Prism' a AuthError++  {-# MINIMAL _AuthError #-}++  -- | An error occured while communicating over HTTP with+  -- the local metadata endpoint.+  _RetrievalError :: Prism' a HttpException++  -- | The named environment variable was not found.+  _MissingEnvError :: Prism' a Text++  -- | The specified credentials file could not be found.+  _MissingFileError :: Prism' a FilePath++  -- | An error occured parsing the credentials file.+  _InvalidFileError :: Prism' a Text++  -- | The specified IAM profile could not be found or deserialised.+  _InvalidIAMError :: Prism' a Text++  _RetrievalError = _AuthError . _RetrievalError+  _MissingEnvError = _AuthError . _MissingEnvError+  _MissingFileError = _AuthError . _MissingFileError+  _InvalidFileError = _AuthError . _InvalidFileError+  _InvalidIAMError = _AuthError . _InvalidIAMError++instance AsAuthError SomeException where+  _AuthError = exception++instance AsAuthError AuthError where+  _AuthError = id++  _RetrievalError = prism RetrievalError $ \case+    RetrievalError e -> Right e+    x -> Left x++  _MissingEnvError = prism MissingEnvError $ \case+    MissingEnvError e -> Right e+    x -> Left x++  _MissingFileError = prism MissingFileError $ \case+    MissingFileError f -> Right f+    x -> Left x++  _InvalidFileError = prism InvalidFileError $ \case+    InvalidFileError e -> Right e+    x -> Left x++  _InvalidIAMError = prism InvalidIAMError $ \case+    InvalidIAMError e -> Right e+    x -> Left x
+ src/Amazonka/Auth/InstanceProfile.hs view
@@ -0,0 +1,95 @@+-- |+-- Module      : Amazonka.Auth.InstanceProfile+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Retrieve authentication credentials from EC2 instance profiles.+module Amazonka.Auth.InstanceProfile where++import Amazonka.Auth.Background+import Amazonka.Auth.Exception+import Amazonka.Data+import Amazonka.EC2.Metadata hiding (region)+import qualified Amazonka.EC2.Metadata as IdentityDocument (IdentityDocument (..))+import Amazonka.Env (Env, Env' (..))+import Amazonka.Prelude+import qualified Control.Exception as Exception+import qualified Data.ByteString.Char8 as BS8+import qualified Data.ByteString.Lazy.Char8 as LBS8+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text++-- | Retrieve the default IAM Profile from the local EC2 instance-data.+--+-- The default IAM profile is determined by Amazon as the first profile found+-- in the response from:+-- @http://169.254.169.254/latest/meta-data/iam/security-credentials/@+--+-- Throws 'RetrievalError' if the HTTP call fails, or 'InvalidIAMError' if+-- the default IAM profile cannot be read.+fromDefaultInstanceProfile ::+  MonadIO m =>+  Env' withAuth ->+  m Env+fromDefaultInstanceProfile env =+  liftIO $ do+    ls <-+      Exception.try $ metadata (manager env) (IAM (SecurityCredentials Nothing))++    case BS8.lines <$> ls of+      Right (x : _) -> fromNamedInstanceProfile (Text.decodeUtf8 x) env+      Left e -> Exception.throwIO (RetrievalError e)+      _ ->+        Exception.throwIO $+          InvalidIAMError "Unable to get default IAM Profile from EC2 metadata"++-- | Lookup a specific IAM Profile by name from the local EC2 instance-data.+--+-- Additionally starts a refresh thread for the given authentication environment.+--+-- The resulting 'IORef' wrapper + timer is designed so that multiple concurrent+-- accesses of 'AuthEnv' from the 'AWS' environment are not required to calculate+-- expiry and sequentially queue to update it.+--+-- The forked timer ensures a singular owner and pre-emptive refresh of the+-- temporary session credentials before expiration.+--+-- A weak reference is used to ensure that the forked thread will eventually+-- terminate when 'Auth' is no longer referenced.+--+-- If no session token or expiration time is present the credentials will+-- be returned verbatim.+fromNamedInstanceProfile ::+  MonadIO m =>+  Text ->+  Env' withAuth ->+  m Env+fromNamedInstanceProfile name env@Env {manager} =+  liftIO $ do+    keys <- fetchAuthInBackground getCredentials+    region <- getRegionFromIdentity++    pure env {auth = Identity keys, region}+  where+    getCredentials =+      Exception.try (metadata manager (IAM . SecurityCredentials $ Just name))+        >>= handleErr (eitherDecode' . LBS8.fromStrict) invalidIAMErr++    getRegionFromIdentity =+      Exception.try (identity manager)+        >>= handleErr (fmap IdentityDocument.region) invalidIdentityErr++    handleErr f g = \case+      Left e -> Exception.throwIO (RetrievalError e)+      Right x -> either (Exception.throwIO . g) pure (f x)++    invalidIAMErr e =+      InvalidIAMError $+        mconcat ["Error parsing IAM profile '", name, "' ", Text.pack e]++    invalidIdentityErr e =+      InvalidIAMError $+        mconcat ["Error parsing Instance Identity Document ", Text.pack e]
+ src/Amazonka/Auth/Keys.hs view
@@ -0,0 +1,122 @@+-- |+-- Module      : Amazonka.Auth.Keys+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Authentication via directly-provided access keys, including+-- optional session token and environment variable lookup.+module Amazonka.Auth.Keys where++import Amazonka.Auth.Exception (_MissingEnvError)+import Amazonka.Core.Lens.Internal (throwingM)+import Amazonka.Data+import Amazonka.Env (Env, Env' (..))+import Amazonka.Prelude+import Amazonka.Types+import Control.Monad.Trans.Maybe (MaybeT (..))+import qualified Data.ByteString.Char8 as BS8+import Data.Foldable (asum)+import qualified System.Environment as Environment++-- | Explicit access and secret keys.+fromKeys :: AccessKey -> SecretKey -> Env' withAuth -> Env+fromKeys a s env =+  env {auth = Identity . Auth $ AuthEnv a (Sensitive s) Nothing Nothing}++-- | Temporary credentials from a STS session consisting of+-- the access key, secret key, and session token.+--+-- /See:/ 'fromTemporarySession'+fromSession ::+  AccessKey -> SecretKey -> SessionToken -> Env' withAuth -> Env+fromSession a s t env =+  env+    { auth =+        Identity . Auth $+          AuthEnv a (Sensitive s) (Just (Sensitive t)) Nothing+    }++-- | Temporary credentials from a STS session consisting of+-- the access key, secret key, session token, and expiration time.+--+-- /See:/ 'fromSession'+fromTemporarySession ::+  AccessKey ->+  SecretKey ->+  SessionToken ->+  UTCTime ->+  Env' withAuth ->+  Env+fromTemporarySession a s t e env =+  env+    { auth =+        Identity . Auth $+          AuthEnv a (Sensitive s) (Just (Sensitive t)) (Just (Time e))+    }++-- | Retrieve access key, secret key and a session token from+-- environment variables. We copy the behaviour of the SDKs and+-- respect the following variables:+--+-- * @AWS_ACCESS_KEY_ID@ (and its alternate name, @AWS_ACCESS_KEY@)+-- * @AWS_SECRET_ACCESS_KEY@ (and its alternate name, @AWS_SECRET_KEY@)+-- * @AWS_SESSION_TOKEN@ (if present)+--+-- Throws 'MissingEnvError' if a required environment variable is+-- empty or unset.+fromKeysEnv :: MonadIO m => Env' withAuth -> m Env+fromKeysEnv env = liftIO $ do+  keys <- Auth <$> lookupKeys+  pure $ env {auth = Identity keys}+  where+    lookupKeys =+      AuthEnv+        <$> lookupAccessKey+        <*> lookupSecretKey+        <*> lookupSessionToken+        <*> pure Nothing++    lookupAccessKey :: IO AccessKey+    lookupAccessKey = do+      mVal <-+        runMaybeT $+          asum+            [ MaybeT (nonEmptyEnv "AWS_ACCESS_KEY_ID"),+              MaybeT (nonEmptyEnv "AWS_ACCESS_KEY")+            ]+      case mVal of+        Nothing ->+          throwingM+            _MissingEnvError+            "Unable to read access key from AWS_ACCESS_KEY_ID (or AWS_ACCESS_KEY)"+        Just v -> pure . AccessKey $ BS8.pack v++    lookupSecretKey :: IO (Sensitive SecretKey)+    lookupSecretKey = do+      mVal <-+        runMaybeT $+          asum+            [ MaybeT (nonEmptyEnv "AWS_SECRET_ACCESS_KEY"),+              MaybeT (nonEmptyEnv "AWS_SECRET_KEY")+            ]+      case mVal of+        Nothing ->+          throwingM+            _MissingEnvError+            "Unable to read secret key from AWS_SECRET_ACCESS_KEY (or AWS_SECRET_KEY)"+        Just v -> pure . Sensitive . SecretKey $ BS8.pack v++    lookupSessionToken :: IO (Maybe (Sensitive SessionToken))+    lookupSessionToken =+      nonEmptyEnv "AWS_SESSION_TOKEN"+        <&> fmap (Sensitive . SessionToken . BS8.pack)++    nonEmptyEnv :: String -> IO (Maybe String)+    nonEmptyEnv var =+      Environment.lookupEnv var <&> \case+        Nothing -> Nothing+        Just "" -> Nothing+        Just v -> Just v
+ src/Amazonka/Auth/SSO.hs view
@@ -0,0 +1,130 @@+-- |+-- Module      : Amazonka.Auth.SSO+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+module Amazonka.Auth.SSO where++import Amazonka.Auth.Background (fetchAuthInBackground)+import Amazonka.Auth.Exception+import Amazonka.Core.Lens.Internal ((^.))+import qualified Amazonka.Crypto as Crypto+import Amazonka.Data.Sensitive+import Amazonka.Data.Time (Time (..))+import Amazonka.Env (Env, Env' (..))+import Amazonka.Prelude+import Amazonka.SSO.GetRoleCredentials as SSO+import qualified Amazonka.SSO.Types as SSO (RoleCredentials (..))+import Amazonka.Send (sendUnsigned)+import Amazonka.Types+import qualified Control.Exception as Exception+import Control.Exception.Lens (handling_, _IOException)+import Control.Monad.Trans.Resource (runResourceT)+import Data.Aeson (FromJSON, decodeFileStrict)+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)++data CachedAccessToken = CachedAccessToken+  { startUrl :: Text,+    region :: Region,+    accessToken :: Sensitive Text,+    expiresAt :: UTCTime+  }+  deriving stock (Show, Eq, Generic)+  deriving anyclass (FromJSON)++{-# INLINE cachedAccessToken_startUrl #-}+cachedAccessToken_startUrl :: Lens' CachedAccessToken Text+cachedAccessToken_startUrl f c@CachedAccessToken {startUrl} = f startUrl <&> \startUrl' -> c {startUrl = startUrl'}++{-# INLINE cachedAccessToken_region #-}+cachedAccessToken_region :: Lens' CachedAccessToken Region+cachedAccessToken_region f c@CachedAccessToken {region} = f region <&> \region' -> (c :: CachedAccessToken) {region = region'}++{-# INLINE cachedAccessToken_accessToken #-}+cachedAccessToken_accessToken :: Lens' CachedAccessToken (Sensitive Text)+cachedAccessToken_accessToken f c@CachedAccessToken {accessToken} = f accessToken <&> \accessToken' -> (c :: CachedAccessToken) {accessToken = accessToken'}++{-# INLINE cachedAccessToken_expiresAt #-}+cachedAccessToken_expiresAt :: Lens' CachedAccessToken UTCTime+cachedAccessToken_expiresAt f c@CachedAccessToken {expiresAt} = f expiresAt <&> \expiresAt' -> c {expiresAt = expiresAt'}++-- | Assume a role using an SSO Token.+--+-- The user must have previously called @aws sso login@, and pass in the path to+-- the cached token file, along with SSO region, account ID and role name.+-- ('Amazonka.Auth.ConfigFile.fromFilePath' understands the @sso_@ variables+-- used by the official AWS CLI and will call 'fromSSO' for you.) This function+-- uses 'fetchAuthInBackground' to refresh the credentials as long as the token+-- in the @sso/cache@ file is not expired. When it has, the user will need to+-- @aws sso login@ again.+--+-- <https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html>+fromSSO ::+  forall m withAuth.+  MonadIO m =>+  FilePath ->+  Region ->+  -- | Account ID+  Text ->+  -- | Role Name+  Text ->+  Env' withAuth ->+  m Env+fromSSO cachedTokenFile ssoRegion accountId roleName env = do+  keys <- liftIO $ fetchAuthInBackground getCredentials+  pure $ env {auth = Identity keys}+  where+    getCredentials = do+      CachedAccessToken {..} <- readCachedAccessToken cachedTokenFile++      -- The Region you SSO through may differ from the Region you intend to+      -- interact with after. The former is handled here, the latter is taken+      -- care of later, in ConfigFile.+      let ssoEnv :: Env' withAuth+          ssoEnv = env {region = ssoRegion}+          getRoleCredentials =+            SSO.newGetRoleCredentials+              roleName+              accountId+              (fromSensitive accessToken)++      resp <- runResourceT $ sendUnsigned ssoEnv getRoleCredentials+      pure . roleCredentialsToAuthEnv $+        resp ^. SSO.getRoleCredentialsResponse_roleCredentials++-- | Return the cached token file for a given @sso_start_url@+--+-- Matches+-- [botocore](https://github.com/boto/botocore/blob/c02f3561f56085b8a3f98501d25b9857b916c10e/botocore/utils.py#L2596-L2597),+-- so that we find tokens produced by @aws sso login@.+relativeCachedTokenFile :: MonadIO m => Text -> m FilePath+relativeCachedTokenFile startUrl = do+  let sha1 = show . Crypto.hashSHA1 $ Text.encodeUtf8 startUrl+  pure $ "/.aws/sso/cache/" <> sha1 <> ".json"++readCachedAccessToken :: MonadIO m => FilePath -> m CachedAccessToken+readCachedAccessToken p = liftIO $+  handling_ _IOException err $ do+    mCache <- decodeFileStrict p+    maybe err pure mCache+  where+    err =+      Exception.throwIO $+        InvalidFileError $+          mconcat+            [ "Unable to read SSO cache. ",+              Text.pack p,+              " is missing or invalid."+            ]++roleCredentialsToAuthEnv :: SSO.RoleCredentials -> AuthEnv+roleCredentialsToAuthEnv rc =+  AuthEnv+    (SSO.accessKeyId rc)+    (SSO.secretAccessKey rc)+    (SSO.sessionToken rc)+    (Time . posixSecondsToUTCTime . fromInteger <$> SSO.expiration rc)
+ src/Amazonka/Auth/STS.hs view
@@ -0,0 +1,141 @@+-- |+-- Module      : Amazonka.Auth.STS+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Retrieve authentication credentials from Secure Token Service+module Amazonka.Auth.STS where++import Amazonka.Auth.Background (fetchAuthInBackground)+import Amazonka.Auth.Exception+import Amazonka.Core.Lens.Internal (throwingM, (^.))+import Amazonka.Env (Env, Env' (..))+import Amazonka.Prelude+import qualified Amazonka.STS as STS+import qualified Amazonka.STS.AssumeRole as STS+import qualified Amazonka.STS.AssumeRoleWithWebIdentity as STS+import Amazonka.Send (send, sendUnsigned)+import Control.Monad.Trans.Resource (runResourceT)+import qualified Data.Text as Text+import qualified Data.Text.IO as Text+import qualified Data.UUID as UUID+import qualified Data.UUID.V4 as UUID+import qualified System.Environment as Environment++-- | Assume a role using the @sts:AssumeRole@ API.+--+-- This is a simplified interface suitable for most purposes, but if+-- you need the full functionality of the @sts:AssumeRole@ API, you+-- will need to craft your own requests using @amazonka-sts@. If you+-- do this, remember to use 'fetchAuthInBackground' so that your+-- application does not get stuck holding temporary credentials which+-- have expired.+fromAssumedRole ::+  MonadIO m =>+  -- | Role ARN+  Text ->+  -- | Role session name+  Text ->+  Env ->+  m Env+fromAssumedRole roleArn roleSessionName env = do+  let getCredentials = do+        let assumeRole = STS.newAssumeRole roleArn roleSessionName+        resp <- runResourceT $ send env assumeRole+        pure $ resp ^. STS.assumeRoleResponse_credentials+  keys <- liftIO $ fetchAuthInBackground getCredentials+  pure env {auth = Identity keys}++-- | https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/+-- Obtain temporary credentials from @sts:AssumeRoleWithWebIdentity@.+--+-- The STS service provides an access key, secret key, session token,+-- and expiration time. Also spawns a refresh thread that will+-- periodically fetch fresh credentials before the current ones+-- expire.+--+-- The implementation is modelled on the C++ SDK:+-- https://github.com/aws/aws-sdk-cpp/blob/6d6dcdbfa377393306bf79585f61baea524ac124/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp#L33+fromWebIdentity ::+  MonadIO m =>+  -- | Path to token file+  FilePath ->+  -- | Role ARN+  Text ->+  -- | Role Session Name+  Maybe Text ->+  Env' withAuth ->+  m Env+fromWebIdentity tokenFile roleArn mSessionName env = do+  -- Mimic the C++ SDK; fall back to a random UUID if the session name is unset.+  sessionName <-+    liftIO $ maybe (UUID.toText <$> UUID.nextRandom) pure mSessionName++  -- We copy the behaviour of the C++ implementation: upon credential+  -- expiration, re-read the token file content but ignore any changes+  -- to environment variables.+  let getCredentials = do+        token <- Text.readFile tokenFile++        let assumeRoleWithWebIdentity =+              STS.newAssumeRoleWithWebIdentity+                roleArn+                sessionName+                token++        resp <- runResourceT $ sendUnsigned env assumeRoleWithWebIdentity+        pure $ resp ^. STS.assumeRoleWithWebIdentityResponse_credentials++  -- As the credentials from STS are temporary, we start a thread that is able+  -- to fetch new ones automatically on expiry.+  keys <- liftIO $ fetchAuthInBackground getCredentials++  pure env {auth = Identity keys}++-- | Obtain temporary credentials from+-- @sts:AssumeRoleWithWebIdentity@, sourcing arguments from standard+-- environment variables:+--+-- * @AWS_WEB_IDENTITY_TOKEN_FILE@+-- * @AWS_ROLE_ARN@+-- * @AWS_ROLE_SESSION_NAME@ (optional)+--+-- Throws 'MissingEnvError' if a required environment variable is+-- empty or unset.+fromWebIdentityEnv ::+  MonadIO m =>+  Env' withAuth ->+  m Env+fromWebIdentityEnv env = liftIO $ do+  tokenFile <- lookupTokenFile+  roleArn <- lookupRoleArn+  mSessionName <- lookupSessionName+  fromWebIdentity tokenFile roleArn mSessionName env+  where+    lookupTokenFile =+      nonEmptyEnv "AWS_WEB_IDENTITY_TOKEN_FILE" >>= \case+        Just v -> pure v+        Nothing ->+          throwingM+            _MissingEnvError+            "Unable to read token file name from AWS_WEB_IDENTITY_TOKEN_FILE"++    lookupRoleArn =+      nonEmptyEnv "AWS_ROLE_ARN" >>= \case+        Just v -> pure $ Text.pack v+        Nothing ->+          throwingM+            _MissingEnvError+            "Unable to read role ARN from AWS_ROLE_ARN"++    lookupSessionName = fmap Text.pack <$> nonEmptyEnv "AWS_ROLE_SESSION_NAME"++    nonEmptyEnv :: String -> IO (Maybe String)+    nonEmptyEnv var =+      Environment.lookupEnv var <&> \case+        Nothing -> Nothing+        Just "" -> Nothing+        Just v -> Just v
+ src/Amazonka/EC2/Metadata.hs view
@@ -0,0 +1,788 @@+{-# LANGUAGE BangPatterns #-}++-- |+-- Module      : Amazonka.EC2.Metadata+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- This module contains functions for retrieving various EC2 metadata from an+-- instance's local metadata endpoint. It assumes that you're running the code+-- on an EC2 instance or have a compatible @instance-data@ endpoint available.+--+-- It is intended to be usable when you need to make metadata calls prior to+-- initialisation of the 'Amazonka.Env.Env'.+module Amazonka.EC2.Metadata+  ( -- * EC2 Instance Check+    isEC2,++    -- * Retrieving Instance Data+    dynamic,+    metadata,+    userdata,+    identity,++    -- ** Path Constructors+    Dynamic (..),+    Metadata (..),+    Autoscaling (..),+    Mapping (..),+    ElasticGpus (..),+    ElasticInference (..),+    Events (..),+    Maintenance (..),+    Recommendations (..),+    IAM (..),+    IdentityCredentialsEC2 (..),+    Interface (..),+    Placement (..),+    Services (..),+    Spot (..),+    Tags (..),++    -- ** Identity Document+    IdentityDocument (..),++    -- *** Lenses+    identityDocument_devpayProductCodes,+    identityDocument_billingProducts,+    identityDocument_version,+    identityDocument_privateIp,+    identityDocument_availabilityZone,+    identityDocument_region,+    identityDocument_instanceId,+    identityDocument_instanceType,+    identityDocument_accountId,+    identityDocument_imageId,+    identityDocument_kernelId,+    identityDocument_ramdiskId,+    identityDocument_architecture,+    identityDocument_pendingTime,+  )+where++import Amazonka.Data+import Amazonka.Prelude+import Amazonka.Types (Region)+import qualified Control.Exception as Exception+import qualified Data.ByteString.Char8 as BS8+import qualified Data.ByteString.Lazy as LBS+import qualified Data.Text as Text+import qualified Network.HTTP.Client as Client+import Network.HTTP.Simple (setRequestHeader, setRequestMethod)++data Dynamic+  = -- | Value showing whether the customer has enabled detailed one-minute+    -- monitoring in CloudWatch.+    --+    -- Valid values: @enabled@ | @disabled@.+    FWS+  | -- | JSON containing instance attributes, such as instance-id,+    -- private IP address, etc.+    -- /See:/ 'identity', 'InstanceDocument'.+    Document+  | -- | Used to verify the document's authenticity and content against the+    -- signature.+    PKCS7+  | -- | Data that can be used by other parties to verify its origin+    -- and authenticity.+    Signature+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Dynamic where+  toText =+    ("dynamic/" <>) . \case+      FWS -> "fws/instance-monitoring"+      Document -> "instance-identity/document"+      PKCS7 -> "instance-identity/pkcs7"+      Signature -> "instance-identity/signature"++-- | Instance metadata categories. The list of supported categories+-- are listed in the [EC2 Documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html).+data Metadata+  = -- | The AMI ID used to launch the instance.+    AMIId+  | -- | If you started more than one instance at the same time, this value+    -- indicates the order in which the instance was launched.+    -- The value of the first instance launched is 0.+    AMILaunchIndex+  | -- | The path to the AMI's manifest file in Amazon S3.+    -- If you used an Amazon EBS-backed AMI to launch the instance,+    -- the returned result is @unknown@.+    AMIManifestPath+  | -- | The AMI IDs of any instances that were rebundled to create this AMI.+    -- This value will only exist if the AMI manifest file contained an+    -- @ancestor-amis@ key.+    AncestorAMIIds+  | -- | See: 'Autoscaling'+    Autoscaling !Autoscaling+  | -- | See: 'Mapping'+    BlockDevice !Mapping+  | -- | See: 'ElasticGpus'+    ElasticGpus !ElasticGpus+  | -- | See 'ElasticInference'+    ElasticInference !ElasticInference+  | -- | See 'Events'+    Events !Events+  | -- | If the EC2 instance is using IP-based naming (IPBN), this is+    -- the private IPv4 DNS hostname of the instance. If the EC2+    -- instance is using Resource-based naming (RBN), this is the+    -- RBN. In cases where multiple network interfaces are present,+    -- this refers to the eth0 device (the device for which the device+    -- number is 0). For more information about IPBN and RBN, see+    -- [Amazon EC2 instance hostname types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html).+    Hostname+  | -- | See: 'IAM'+    IAM !IAM+  | -- | See: 'IdentityCredentialsEC2'+    IdentityCredentialsEC2 !IdentityCredentialsEC2+  | -- | Notifies the instance that it should reboot in preparation for bundling.+    -- Valid values: @none@ | @shutdown@ | @bundle-pending@.+    InstanceAction+  | -- | The ID of this instance.+    InstanceId+  | -- | The purchasing option of this instance. For more+    -- information, see+    -- [Instance purchasing options](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-purchasing-options.html).+    InstanceLifeCycle+  | -- | The type of instance. For more information, see+    -- [Instance types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html).+    InstanceType+  | -- | The IPv6 address of the instance. In cases where multiple+    -- network interfaces are present, this refers to the eth0 device+    -- (the device for which the device number is 0) network interface+    -- and the first IPv6 address assigned. If no IPv6 address exists+    -- on network interface[0], this item is not set and results in an+    -- HTTP 404 response.+    IPV6+  | -- | The ID of the kernel launched with this instance, if applicable.+    KernelId+  | -- | In cases where multiple network interfaces are present, this+    -- refers to the eth0 device (the device for which the device+    -- number is 0). If the EC2 instance is using IP-based naming+    -- (IPBN), this is the private IPv4 DNS hostname of the+    -- instance. If the EC2 instance is using Resource-based naming+    -- (RBN), this is the RBN. For more information about IPBN, RBN,+    -- and EC2 instance naming, see+    -- [Amazon EC2 instance hostname types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html).+    LocalHostname+  | -- | The private IPv4 address of the instance. In cases where+    -- multiple network interfaces are present, this refers to the+    -- eth0 device (the device for which the device number is 0). If+    -- this is an IPv6-only instance, this item is not set and results+    -- in an HTTP 404 response.+    LocalIPV4+  | -- | The instance's media access control (MAC) address. In cases+    -- where multiple network interfaces are present, this refers to+    -- the eth0 device (the device for which the device number is 0).+    MAC+  | -- | See: 'Interface'+    Network !Text !Interface+  | -- | See: 'Placement'+    Placement !Placement+  | -- | AWS Marketplace product codes associated with the instance,+    -- if any.+    ProductCodes+  | -- | The instance's public DNS (IPv4). This category is only+    -- returned if the @enableDnsHostnames@ attribute is set to+    -- @true@. For more information, see+    -- [Using DNS with Your VPC](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html)+    -- in the /Amazon VPC User Guide/. If the instance only has a+    -- public-IPv6 address and no public-IPv4 address, this item is+    -- not set and results in an HTTP 404 response.+    PublicHostname+  | -- | The public IP address. If an Elastic IP address is associated with the+    -- instance, the value returned is the Elastic IP address.+    PublicIPV4+  | -- | Public key. Only available if supplied at instance launch time.+    OpenSSHKey+  | -- | The ID of the RAM disk specified at launch time, if applicable.+    RAMDiskId+  | -- | ID of the reservation.+    ReservationId+  | -- | The names of the security groups applied to the instance.+    --+    -- After launch, you can change the security groups of the+    -- instances. Such changes are reflected here and in+    -- @network\/interfaces\/macs\/${mac}\/security-groups@.+    SecurityGroups+  | -- | See: 'Services'+    Services !Services+  | -- | See: 'Spot'+    Spot !Spot+  | -- | See: 'Tags'+    Tags !Tags+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Metadata where+  toText =+    ("meta-data/" <>) . \case+      AMIId -> "ami-id"+      AMILaunchIndex -> "ami-launch-index"+      AMIManifestPath -> "ami-manifest-path"+      AncestorAMIIds -> "ancestor-ami-ids"+      Autoscaling m -> "autoscaling/" <> toText m+      BlockDevice m -> "block-device-mapping/" <> toText m+      Hostname -> "hostname"+      ElasticGpus m -> "elastic-gpus/" <> toText m+      ElasticInference m -> "elastic-inference/" <> toText m+      Events m -> "events/" <> toText m+      IAM m -> "iam/" <> toText m+      IdentityCredentialsEC2 m -> "identity-credentials/ec2/" <> toText m+      InstanceAction -> "instance-action"+      InstanceId -> "instance-id"+      InstanceLifeCycle -> "instance-life-cycle"+      InstanceType -> "instance-type"+      IPV6 -> "ipv6"+      KernelId -> "kernel-id"+      LocalHostname -> "local-hostname"+      LocalIPV4 -> "local-ipv4"+      MAC -> "mac"+      Network n m -> "network/interfaces/macs/" <> toText n <> "/" <> toText m+      Placement m -> "placement/" <> toText m+      ProductCodes -> "product-codes"+      PublicHostname -> "public-hostname"+      PublicIPV4 -> "public-ipv4"+      OpenSSHKey -> "public-keys/0/openssh-key"+      RAMDiskId -> "ramdisk-id"+      ReservationId -> "reservation-id"+      SecurityGroups -> "security-groups"+      Services m -> "services/" <> toText m+      Spot m -> "spot/" <> toText m+      Tags m -> "tags/" <> toText m++-- | Metadata keys for @autoscaling/*@.+data Autoscaling+  = -- | Value showing the target Auto Scaling lifecycle state that an+    -- Auto Scaling instance is transitioning to. Present when the+    -- instance transitions to one of the target lifecycle states+    -- after March 10, 2022. Possible values: @Detached@ | @InService@+    -- | @Standby@ | @Terminated@ | @Warmed:Hibernated@ |+    -- @Warmed:Running@ | @Warmed:Stopped@ | @Warmed:Terminated@. See+    -- [Retrieve the target lifecycle state through instance metadata](https://docs.aws.amazon.com/autoscaling/ec2/userguide/retrieving-target-lifecycle-state-through-imds.html)+    -- in the /Amazon EC2 Auto Scaling User Guide/.+    TargetLifecycleState+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Autoscaling where+  toText = \case+    TargetLifecycleState -> "target-lifecycle-state"++-- | Metadata keys for @block-device-mapping/*@.+data Mapping+  = -- | The virtual device that contains the root/boot file system.+    AMI+  | -- | The virtual devices associated with Amazon EBS volumes, if present.+    -- This value is only available in metadata if it is present at launch time.+    -- The N indicates the index of the Amazon EBS volume (such as ebs1 or ebs2).+    EBS !Int+  | -- | The virtual devices associated with ephemeral devices, if present.+    -- The N indicates the index of the ephemeral volume.+    Ephemeral !Int+  | -- | The virtual devices or partitions associated with the root devices,+    -- or partitions on the virtual device, where the root (/ or C:) file system+    -- is associated with the given instance.+    Root+  | -- | The virtual devices associated with swap. Not always present.+    Swap+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Mapping where+  toText = \case+    AMI -> "ami"+    EBS n -> "ebs" <> toText n+    Ephemeral n -> "ephemeral" <> toText n+    Root -> "root"+    Swap -> "root"++-- | Metadata keys for @elastic-gpus/*@.+newtype ElasticGpus+  = -- | If there is an Elastic GPU attached to the instance, contains+    -- a JSON string with information about the Elastic GPU, including+    -- its ID and connection information.+    EGAssociations Text+  deriving stock (Eq, Ord, Show, Generic)++instance ToText ElasticGpus where+  toText = \case+    EGAssociations gpuId -> "associations/" <> gpuId++-- | Metadata keys for @elastic-inference/*@.+newtype ElasticInference+  = -- | If there is an Elastic Inference accelerator attached to the+    -- instance, contains a JSON string with information about the+    -- Elastic Inference accelerator, including its ID and type.+    EIAssociations Text+  deriving stock (Eq, Ord, Show, Generic)++instance ToText ElasticInference where+  toText = \case+    EIAssociations eiId -> "associations/" <> eiId++-- | Metadata keys for @events/*@.+data Events+  = Maintenance !Maintenance+  | Recommendations !Recommendations+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Events where+  toText = \case+    Maintenance m -> "maintenance/" <> toText m+    Recommendations m -> "recommendations/" <> toText m++-- | Metadata keys for @events/maintenance/*@.+data Maintenance+  = -- | If there are completed or canceled maintenance events for the+    -- instance, contains a JSON string with information about the+    -- events. For more information, see+    -- [To view event history about completed or canceled events](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-instances-status-check_sched.html#viewing-event-history).+    History+  | -- | If there are active maintenance events for the instance,+    -- contains a JSON string with information about the events. For+    -- more information, see+    -- [View scheduled events](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-instances-status-check_sched.html#viewing_scheduled_events).+    Scheduled+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Maintenance where+  toText = \case+    History -> "history"+    Scheduled -> "scheduled"++-- | Metadata keys for @events\/recommendations\/*@.+data Recommendations+  = -- | The approximate time, in UTC, when the EC2 instance rebalance+    -- recommendation notification is emitted for the instance. The+    -- following is an example of the metadata for this category:+    -- @{"noticeTime": "2020-11-05T08:22:00Z"}@. This category is+    -- available only after the notification is emitted. For more+    -- information, see+    -- [EC2 instance rebalance recommendations](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/rebalance-recommendations.html).+    Rebalance+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Recommendations where+  toText = \case+    Rebalance -> "rebalance"++-- | Metadata keys for @iam/*@.+data IAM+  = -- | If there is an IAM role associated with the instance,+    -- contains information about the last time the instance profile+    -- was updated, including the instance's LastUpdated date,+    -- InstanceProfileArn, and InstanceProfileId. Otherwise, not+    -- present.+    Info+  | -- | If there is an IAM role associated with the instance,+    -- @role-name@ is the name of the role, and @role-name@ contains the+    -- temporary security credentials associated with the role (for+    -- more information, see+    -- [Retrieve security credentials from instance metadata](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#instance-metadata-security-credentials)).+    -- Otherwise, not present.+    --+    -- See: 'Auth' for JSON deserialisation.+    SecurityCredentials (Maybe Text)+  deriving stock (Eq, Ord, Show, Generic)++instance ToText IAM where+  toText = \case+    Info -> "info"+    SecurityCredentials r -> "security-credentials/" <> maybe mempty toText r++-- | Metadata keys for @identity-credentials\/ec2\/*@.+data IdentityCredentialsEC2+  = -- | Information about the credentials in+    -- @identity-credentials/ec2/security-credentials/ec2-instance@.+    ICEInfo+  | -- | Credentials for the instance identity role that allow+    -- on-instance software to identify itself to AWS to support+    -- features such as EC2 Instance Connect and AWS Systems Manager+    -- Default Host Management Configuration. These credentials have+    -- no policies attached, so they have no additional AWS API+    -- permissions beyond identifying the instance to the AWS+    -- feature. For more information, see [Instance identity+    -- roles](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-identity-roles.html).+    ICESecurityCredentials+  deriving stock (Eq, Ord, Show, Generic)++instance ToText IdentityCredentialsEC2 where+  toText = \case+    ICEInfo -> "info"+    ICESecurityCredentials -> "security-credentials/ec2-instance"++-- | Metadata keys for @network\/interfaces\/macs\/${mac}\/*@.+data Interface+  = -- | The unique device number associated with that interface. The+    -- device number corresponds to the device name; for example, a+    -- @device-number@ of 2 is for the eth2 device. This category+    -- corresponds to the @DeviceIndex@ and @device-index@ fields that+    -- are used by the Amazon EC2 API and the EC2 commands for the AWS+    -- CLI.+    IDeviceNumber+  | -- | The ID of the network interface.+    IInterfaceId+  | -- | The private IPv4 addresses that are associated with each public-ip+    -- address and assigned to that interface.+    IIPV4Associations !Text+  | -- | The IPv6 addresses associated with the interface. Returned+    -- only for instances launched into a VPC.+    IIPV6s+  | -- | The private IPv4 DNS hostname of the instance. In cases where+    -- multiple network interfaces are present, this refers to the+    -- eth0 device (the device for which the device number is 0). If+    -- this is a IPv6-only instance, this is the resource-based+    -- name. For more information about IPBN and RBN, see+    -- [Amazon EC2 instance hostname types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html).+    ILocalHostname+  | -- | The private IPv4 addresses associated with the interface. If+    -- this is an IPv6-only network interface, this item is not set+    -- and results in an HTTP 404 response.+    ILocalIPV4s+  | -- | The instance's MAC address.+    IMAC+  | -- | The index of the network card. Some instance types support multiple network cards.+    INetworkCardIndex+  | -- | The ID of the owner of the network interface. In multiple-interface+    -- environments, an interface can be attached by a third party, such as+    -- Elastic Load Balancing. Traffic on an interface is always billed to+    -- the interface owner.+    IOwnerId+  | -- | The interface's public DNS (IPv4). This category is only+    -- returned if the @enableDnsHostnames@ attribute is set to+    -- @true@. For more information, see+    -- [Using DNS with Your VPC](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html)+    -- in the /Amazon VPC User Guide/. If the instance only has a+    -- public-IPv6 address and no public-IPv4 address, this item is+    -- not set and results in an HTTP 404 response.+    IPublicHostname+  | -- | The Elastic IP addresses associated with the interface. There may be+    -- multiple IP addresses on an instance.+    IPublicIPV4s+  | -- | Security groups to which the network interface belongs.+    ISecurityGroups+  | -- | The IDs of the security groups to which the network interface belongs.+    ISecurityGroupIds+  | -- | The ID of the subnet in which the interface resides.+    ISubnetId+  | -- | The IPv4 CIDR block of the subnet in which the interface resides.+    ISubnetIPV4_CIDRBlock+  | -- | The IPv6 CIDR block of the subnet in which the interface resides.+    ISubnetIPV6_CIDRBlock+  | -- | The ID of the VPC in which the interface resides.+    IVPCId+  | -- | The primary IPv4 CIDR block of the VPC.+    IVPCIPV4_CIDRBlock+  | -- | The IPv4 CIDR blocks for the VPC.+    IVPCIPV4_CIDRBlocks+  | -- | The IPv6 CIDR block of the VPC in which the interface resides.+    IVPCIPV6_CIDRBlocks+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Interface where+  toText = \case+    IDeviceNumber -> "device-number"+    IInterfaceId -> "interface-id"+    IIPV4Associations ip -> "ipv4-associations/" <> toText ip+    IIPV6s -> "ipv6s"+    ILocalHostname -> "local-hostname"+    ILocalIPV4s -> "local-ipv4s"+    IMAC -> "mac"+    INetworkCardIndex -> "network-card-index"+    IOwnerId -> "owner-id"+    IPublicHostname -> "public-hostname"+    IPublicIPV4s -> "public-ipv4s"+    ISecurityGroups -> "security-groups"+    ISecurityGroupIds -> "security-group-ids"+    ISubnetId -> "subnet-id"+    ISubnetIPV4_CIDRBlock -> "subnet-ipv4-cidr-block"+    ISubnetIPV6_CIDRBlock -> "subnet-ipv6-cidr-block"+    IVPCId -> "vpc-id"+    IVPCIPV4_CIDRBlock -> "vpc-ipv4-cidr-block"+    IVPCIPV4_CIDRBlocks -> "vpc-ipv4-cidr-blocks"+    IVPCIPV6_CIDRBlocks -> "vpc-ipv6-cidr-blocks"++-- | Metadata keys for @placement/*@.+data Placement+  = -- | The Availability Zone in which the instance launched.+    AvailabilityZone+  | -- | The static Availability Zone ID in which the instance is+    -- launched. The Availability Zone ID is consistent across+    -- accounts. However, it might be different from the Availability+    -- Zone, which can vary by account.+    AvailabilityZoneId+  | -- | The name of the placement group in which the instance is launched.+    GroupName+  | -- | The ID of the host on which the instance is+    -- launched. Applicable only to Dedicated Hosts.+    HostId+  | -- | The number of the partition in which the instance is launched.+    PartitionNumber+  | -- | The AWS Region in which the instance is launched.+    Region+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Placement where+  toText = \case+    AvailabilityZone -> "availability-zone"+    AvailabilityZoneId -> "availability-zone-id"+    GroupName -> "group-name"+    HostId -> "host-id"+    PartitionNumber -> "partition-number"+    Region -> "region"++-- | Metadata keys for @services/*@.+data Services+  = -- | The domain for AWS resources for the Region.+    Domain+  | -- | The partition that the resource is in. For standard AWS+    -- Regions, the partition is @aws@. If you have resources in other+    -- partitions, the partition is @aws-${partitionname}@. For example,+    -- the partition for resources in the China (Beijing) Region is+    -- @aws-cn@.+    Partition+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Services where+  toText = \case+    Domain -> "domain"+    Partition -> "partition"++-- | Metadata keys for @spot/*@.+data Spot+  = -- | The action (hibernate, stop, or terminate) and the+    -- approximate time, in UTC, when the action will occur. This item+    -- is present only if the Spot Instance has been marked for+    -- hibernate, stop, or terminate. For more information, see+    -- [instance-action](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-instance-termination-notices.html#instance-action-metadata).+    SInstanceAction+  | -- | The approximate time, in UTC, that the operating system for+    -- your Spot Instance will receive the shutdown signal. This item+    -- is present and contains a time value (for example,+    -- 2015-01-05T18:02:00Z) only if the Spot Instance has been marked+    -- for termination by Amazon EC2. The termination-time item is not+    -- set to a time if you terminated the Spot Instance yourself. For+    -- more information, see+    -- [termination-time](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-instance-termination-notices.html#termination-time-metadata).+    STerminationTime+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Spot where+  toText = \case+    SInstanceAction -> "instance-action"+    STerminationTime -> "termination-time"++-- | Metadata keys for @tags/*@.+data Tags+  = -- | The instance tags associated with the instance. Only+    -- available if you explicitly allow access to tags in instance+    -- metadata. For more information, see+    -- [Allow access to tags in instance metadata](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html#allow-access-to-tags-in-IMDS).+    Instance+  deriving stock (Eq, Ord, Show, Generic)++instance ToText Tags where+  toText = \case+    Instance -> "instance"++latest :: Text+latest = "http://169.254.169.254/latest/"++-- | Test whether the underlying host is running on EC2 by+-- making an HTTP request to @http://instance-data/latest@.+isEC2 :: MonadIO m => Client.Manager -> m Bool+isEC2 m = liftIO (Exception.catch req err)+  where+    req = do+      !_ <- get m "http://instance-data/latest"++      return True++    err :: Client.HttpException -> IO Bool+    err = const (return False)++-- | Retrieve the specified 'Dynamic' data.+--+-- Throws 'HttpException' if HTTP communication fails.+dynamic :: MonadIO m => Client.Manager -> Dynamic -> m ByteString+dynamic m = get m . mappend latest . toText++-- | Retrieve the specified 'Metadata'.+--+-- Throws 'HttpException' if HTTP communication fails.+metadata :: MonadIO m => Client.Manager -> Metadata -> m ByteString+metadata m = get m . mappend latest . toText++-- | Retrieve the user data. Returns 'Nothing' if no user data is assigned+-- to the instance.+--+-- Throws 'HttpException' if HTTP communication fails.+userdata :: MonadIO m => Client.Manager -> m (Maybe ByteString)+userdata m =+  liftIO $+    Exception.try (get m (latest <> "user-data")) >>= \case+      Left (Client.HttpExceptionRequest _ (Client.StatusCodeException rs _))+        | fromEnum (Client.responseStatus rs) == 404 ->+            return Nothing+      --+      Left e -> Exception.throwIO e+      --+      Right b -> pure (Just b)++-- | Represents an instance's identity document.+--+-- /Note:/ Fields such as '_instanceType' are represented as unparsed 'Text' and+-- will need to be manually parsed using 'fromText' when the relevant types+-- from a library such as "Amazonka.EC2" are brought into scope.+data IdentityDocument = IdentityDocument+  { devpayProductCodes :: Maybe [Text],+    billingProducts :: Maybe [Text],+    version :: Maybe Text,+    privateIp :: Maybe Text,+    availabilityZone :: Text,+    region :: Region,+    instanceId :: Text,+    instanceType :: Text,+    accountId :: Text,+    imageId :: Maybe Text,+    kernelId :: Maybe Text,+    ramdiskId :: Maybe Text,+    architecture :: Maybe Text,+    pendingTime :: Maybe ISO8601+  }+  deriving stock (Eq, Show, Generic)++instance FromJSON IdentityDocument where+  parseJSON = withObject "dynamic/instance-identity/document" $ \o -> do+    devpayProductCodes <- o .:? "devpayProductCodes"+    billingProducts <- o .:? "billingProducts"+    privateIp <- o .:? "privateIp"+    version <- o .:? "version"+    availabilityZone <- o .: "availabilityZone"+    region <- o .: "region"+    instanceId <- o .: "instanceId"+    instanceType <- o .: "instanceType"+    accountId <- o .: "accountId"+    imageId <- o .:? "imageId"+    kernelId <- o .:? "kernelId"+    ramdiskId <- o .:? "ramdiskId"+    architecture <- o .:? "architecture"+    pendingTime <- o .:? "pendingTime"+    pure IdentityDocument {..}++instance ToJSON IdentityDocument where+  toJSON IdentityDocument {..} =+    object+      [ "devpayProductCodes" .= devpayProductCodes,+        "billingProducts" .= billingProducts,+        "privateIp" .= privateIp,+        "version" .= version,+        "availabilityZone" .= availabilityZone,+        "region" .= region,+        "instanceId" .= instanceId,+        "instanceType" .= instanceType,+        "accountId" .= accountId,+        "imageId" .= imageId,+        "kernelId" .= kernelId,+        "ramdiskId" .= ramdiskId,+        "architecture" .= architecture+      ]++{-# INLINE identityDocument_devpayProductCodes #-}+identityDocument_devpayProductCodes :: Lens' IdentityDocument (Maybe [Text])+identityDocument_devpayProductCodes f i@IdentityDocument {devpayProductCodes} = f devpayProductCodes <&> \devpayProductCodes' -> i {devpayProductCodes = devpayProductCodes'}++{-# INLINE identityDocument_billingProducts #-}+identityDocument_billingProducts :: Lens' IdentityDocument (Maybe [Text])+identityDocument_billingProducts f i@IdentityDocument {billingProducts} = f billingProducts <&> \billingProducts' -> i {billingProducts = billingProducts'}++{-# INLINE identityDocument_version #-}+identityDocument_version :: Lens' IdentityDocument (Maybe Text)+identityDocument_version f i@IdentityDocument {version} = f version <&> \version' -> i {version = version'}++{-# INLINE identityDocument_privateIp #-}+identityDocument_privateIp :: Lens' IdentityDocument (Maybe Text)+identityDocument_privateIp f i@IdentityDocument {privateIp} = f privateIp <&> \privateIp' -> i {privateIp = privateIp'}++{-# INLINE identityDocument_availabilityZone #-}+identityDocument_availabilityZone :: Lens' IdentityDocument Text+identityDocument_availabilityZone f i@IdentityDocument {availabilityZone} = f availabilityZone <&> \availabilityZone' -> i {availabilityZone = availabilityZone'}++{-# INLINE identityDocument_region #-}+identityDocument_region :: Lens' IdentityDocument Region+identityDocument_region f i@IdentityDocument {region} = f region <&> \region' -> i {region = region'}++{-# INLINE identityDocument_instanceId #-}+identityDocument_instanceId :: Lens' IdentityDocument Text+identityDocument_instanceId f i@IdentityDocument {instanceId} = f instanceId <&> \instanceId' -> i {instanceId = instanceId'}++{-# INLINE identityDocument_instanceType #-}+identityDocument_instanceType :: Lens' IdentityDocument Text+identityDocument_instanceType f i@IdentityDocument {instanceType} = f instanceType <&> \instanceType' -> i {instanceType = instanceType'}++{-# INLINE identityDocument_accountId #-}+identityDocument_accountId :: Lens' IdentityDocument Text+identityDocument_accountId f i@IdentityDocument {accountId} = f accountId <&> \accountId' -> i {accountId = accountId'}++{-# INLINE identityDocument_imageId #-}+identityDocument_imageId :: Lens' IdentityDocument (Maybe Text)+identityDocument_imageId f i@IdentityDocument {imageId} = f imageId <&> \imageId' -> i {imageId = imageId'}++{-# INLINE identityDocument_kernelId #-}+identityDocument_kernelId :: Lens' IdentityDocument (Maybe Text)+identityDocument_kernelId f i@IdentityDocument {kernelId} = f kernelId <&> \kernelId' -> i {kernelId = kernelId'}++{-# INLINE identityDocument_ramdiskId #-}+identityDocument_ramdiskId :: Lens' IdentityDocument (Maybe Text)+identityDocument_ramdiskId f i@IdentityDocument {ramdiskId} = f ramdiskId <&> \ramdiskId' -> i {ramdiskId = ramdiskId'}++{-# INLINE identityDocument_architecture #-}+identityDocument_architecture :: Lens' IdentityDocument (Maybe Text)+identityDocument_architecture f i@IdentityDocument {architecture} = f architecture <&> \architecture' -> i {architecture = architecture'}++{-# INLINE identityDocument_pendingTime #-}+identityDocument_pendingTime :: Lens' IdentityDocument (Maybe ISO8601)+identityDocument_pendingTime f i@IdentityDocument {pendingTime} = f pendingTime <&> \pendingTime' -> i {pendingTime = pendingTime'}++-- | Retrieve the instance's identity document, detailing various EC2 metadata.+--+-- You can alternatively retrieve the raw unparsed identity document by using+-- 'dynamic' and the 'Document' path.+--+-- /See:/ <http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html AWS Instance Identity Documents>.+identity ::+  MonadIO m =>+  Client.Manager ->+  m (Either String IdentityDocument)+identity m = eitherDecode . LBS.fromStrict <$> dynamic m Document++get :: MonadIO m => Client.Manager -> Text -> m ByteString+get m url = liftIO $ do+  token <- strip <$> requestToken+  strip <$> requestWith (addToken token) m url+  where+    requestToken =+      requestWith+        ( setRequestMethod "PUT"+            . setRequestHeader "X-aws-ec2-metadata-token-ttl-seconds" ["60"]+        )+        m+        (latest <> "api/token")++    addToken token = setRequestHeader "X-aws-ec2-metadata-token" [token]++    strip bs+      | BS8.isSuffixOf "\n" bs = BS8.init bs+      | otherwise = bs++requestWith ::+  (Client.Request -> Client.Request) ->+  Client.Manager ->+  Text ->+  IO ByteString+requestWith modifyRequest m url = do+  rq <- Client.parseUrlThrow (Text.unpack url)+  rs <- Client.httpLbs (modifyRequest rq) m++  return . LBS.toStrict $ Client.responseBody rs
+ src/Amazonka/Env.hs view
@@ -0,0 +1,237 @@+-- |+-- Module      : Amazonka.Env+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Environment and AWS specific configuration needed to perform AWS+-- requests.+module Amazonka.Env+  ( -- * Creating the Environment+    newEnv,+    newEnvFromManager,+    newEnvNoAuth,+    newEnvNoAuthFromManager,+    Env' (..),+    Env,+    EnvNoAuth,+    authMaybe,+    lookupRegion,++    -- ** Lenses+    env_region,+    env_logger,+    env_hooks,+    env_retryCheck,+    env_overrides,+    env_manager,+    env_auth,++    -- * Overriding Default Configuration+    overrideService,+    configureService,++    -- * 'Env' override helpers+    globalTimeout,+    once,++    -- * Retry HTTP Exceptions+    retryConnectionFailure,+  )+where++import Amazonka.Core.Lens.Internal (Lens)+import Amazonka.Env.Hooks (Hooks, addLoggingHooks, noHooks)+import Amazonka.Logger (Logger)+import Amazonka.Prelude+import Amazonka.Types hiding (timeout)+import qualified Amazonka.Types as Service (Service (..))+import qualified Data.Function as Function+import qualified Data.Text as Text+import qualified Network.HTTP.Client as Client+import qualified Network.HTTP.Conduit as Client.Conduit+import System.Environment as Environment++-- | An environment with auth credentials. Most AWS requests need one+-- of these, and you can create one with 'Amazonka.Env.newEnv'.+type Env = Env' Identity++-- | An environment with no auth credentials. Used for certain+-- requests which need to be unsigned, like+-- @sts:AssumeRoleWithWebIdentity@, and you can create one with+-- 'Amazonka.Env.newEnvNoAuth' if you need it.+type EnvNoAuth = Env' Proxy++-- | The environment containing the parameters required to make AWS requests.+--+-- This type tracks whether or not we have credentials at the type+-- level, to avoid "presigning" requests when we lack auth+-- information.+data Env' withAuth = Env+  { region :: Region,+    logger :: Logger,+    hooks :: ~Hooks,+    retryCheck :: Int -> Client.HttpException -> Bool,+    overrides :: Service -> Service,+    manager :: Client.Manager,+    auth :: withAuth Auth+  }+  deriving stock (Generic)++{-# INLINE env_region #-}+env_region :: Lens' (Env' withAuth) Region+env_region f e@Env {region} = f region <&> \region' -> e {region = region'}++{-# INLINE env_logger #-}+env_logger :: Lens' (Env' withAuth) Logger+env_logger f e@Env {logger} = f logger <&> \logger' -> e {logger = logger'}++{-# INLINE env_hooks #-}+env_hooks :: Lens' (Env' withAuth) Hooks+env_hooks f e@Env {hooks} = f hooks <&> \hooks' -> e {hooks = hooks'}++{-# INLINE env_retryCheck #-}+env_retryCheck :: Lens' (Env' withAuth) (Int -> Client.HttpException -> Bool)+env_retryCheck f e@Env {retryCheck} = f retryCheck <&> \retryCheck' -> e {retryCheck = retryCheck'}++{-# INLINE env_overrides #-}+env_overrides :: Lens' (Env' withAuth) (Service -> Service)+env_overrides f e@Env {overrides} = f overrides <&> \overrides' -> e {overrides = overrides'}++{-# INLINE env_manager #-}+env_manager :: Lens' (Env' withAuth) Client.Manager+env_manager f e@Env {manager} = f manager <&> \manager' -> e {manager = manager'}++{-# INLINE env_auth #-}+env_auth :: Lens (Env' withAuth) (Env' withAuth') (withAuth Auth) (withAuth' Auth)+env_auth f e@Env {auth} = f auth <&> \auth' -> e {auth = auth'}++-- | Creates a new environment with a new 'Client.Manager' without+-- debug logging and uses the provided function to expand/discover+-- credentials. Record updates or lenses can be used to further+-- configure the resulting 'Env'.+--+-- /Since:/ @1.5.0@ - The region is now retrieved from the @AWS_REGION@ environment+-- variable (identical to official SDKs), or defaults to @us-east-1@.+-- You can override the 'Env' region by updating its 'region' field.+--+-- /Since:/ @1.3.6@ - The default logic for retrying 'HttpException's now uses+-- 'retryConnectionFailure' to retry specific connection failure conditions up to 3 times.+-- Previously only service specific errors were automatically retried.+-- This can be reverted to the old behaviour by resetting the 'Env''s+-- 'retryCheck' field to @(\\_ _ -> False)@.+--+-- Throws 'AuthError' when environment variables or IAM profiles cannot be read.+--+-- /See:/ 'newEnvFromManager'.+newEnv ::+  MonadIO m =>+  -- | Credential discovery mechanism, often 'Amazonka.Auth.discover'.+  (EnvNoAuth -> m Env) ->+  m Env+newEnv = (newEnvNoAuth >>=)++-- | Creates a new environment, but with an existing 'Client.Manager'.+newEnvFromManager ::+  MonadIO m =>+  Client.Manager ->+  -- | Credential discovery mechanism.+  (EnvNoAuth -> m Env) ->+  m Env+newEnvFromManager manager = (newEnvNoAuthFromManager manager >>=)++-- | Generate an environment without credentials, which may only make+-- unsigned requests. Sets the region based on the @AWS_REGION@+-- environment variable, or 'NorthVirginia' if unset.+--+-- This lets us support calls like the+-- <https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html sts:AssumeRoleWithWebIdentity>+-- operation, which needs to make an unsigned request to pass the+-- token from an identity provider.+newEnvNoAuth :: MonadIO m => m EnvNoAuth+newEnvNoAuth =+  liftIO (Client.newManager Client.Conduit.tlsManagerSettings)+    >>= newEnvNoAuthFromManager++-- | Generate an environment without credentials, passing in an+-- explicit 'Client.Manager'.+newEnvNoAuthFromManager :: MonadIO m => Client.Manager -> m EnvNoAuth+newEnvNoAuthFromManager manager = do+  mRegion <- lookupRegion+  pure+    Env+      { region = fromMaybe NorthVirginia mRegion,+        logger = \_ _ -> pure (),+        hooks = addLoggingHooks noHooks,+        retryCheck = retryConnectionFailure 3,+        overrides = id,+        manager,+        auth = Proxy+      }++-- | Get "the" 'Auth' from an 'Env'', if we can.+authMaybe :: Foldable withAuth => Env' withAuth -> Maybe Auth+authMaybe = foldr (const . Just) Nothing . auth++-- | Look up the region in the @AWS_REGION@ environment variable.+lookupRegion :: MonadIO m => m (Maybe Region)+lookupRegion =+  liftIO $+    Environment.lookupEnv "AWS_REGION" <&> \case+      Nothing -> Nothing+      Just "" -> Nothing+      Just t -> Just . Region' $ Text.pack t++-- | Retry the subset of transport specific errors encompassing connection+-- failure up to the specific number of times.+retryConnectionFailure :: Int -> Int -> Client.HttpException -> Bool+retryConnectionFailure limit n = \case+  Client.InvalidUrlException {} -> False+  Client.HttpExceptionRequest _ ex+    | n >= limit -> False+    | otherwise ->+        case ex of+          Client.NoResponseDataReceived -> True+          Client.ConnectionTimeout -> True+          Client.ConnectionClosed -> True+          Client.ConnectionFailure {} -> True+          Client.InternalException {} -> True+          _other -> False++-- | Provide a function which will be added to the existing stack+-- of overrides applied to all service configurations.+overrideService :: (Service -> Service) -> Env' withAuth -> Env' withAuth+overrideService f env = env {overrides = f . overrides env}++-- | Configure a specific service. All requests belonging to the+-- supplied service will use this configuration instead of the default.+--+-- It's suggested you modify the default service configuration,+-- such as @Amazonka.DynamoDB.defaultService@.+configureService :: Service -> Env' withAuth -> Env' withAuth+configureService s = overrideService f+  where+    f x+      | Function.on (==) Service.abbrev s x = s+      | otherwise = x++-- | Override the timeout value for this 'Env'.+--+-- Default timeouts are chosen by considering:+--+-- * This 'timeout', if set.+--+-- * The related 'Service' timeout for the sent request if set. (Usually 70s)+--+-- * The 'manager' timeout if set.+--+-- * The default 'ClientRequest' timeout. (Approximately 30s)+globalTimeout :: Seconds -> Env' withAuth -> Env' withAuth+globalTimeout n = overrideService $ \s -> s {Service.timeout = Just n}++-- | Disable any retry logic for an 'Env', so that any requests will+-- at most be sent once.+once :: Env' withAuth -> Env' withAuth+once = overrideService $ \s@Service {retry} -> s {retry = retry {attempts = 0}}
+ src/Amazonka/Env.hs-boot view
@@ -0,0 +1,17 @@+module Amazonka.Env where++import Amazonka.Logger (Logger)+import Amazonka.Types (Region, Service, Auth)+import Amazonka.Prelude+import qualified Network.HTTP.Client as Client+import {-# SOURCE #-} Amazonka.Env.Hooks (Hooks)++data Env' (withAuth :: Type -> Type) = Env+  { region :: Region,+    logger :: Logger,+    hooks :: ~Hooks,+    retryCheck :: Int -> Client.HttpException -> Bool,+    overrides :: Service -> Service,+    manager :: Client.Manager,+    auth :: withAuth Auth+  }
+ src/Amazonka/Env/Hooks.hs view
@@ -0,0 +1,605 @@+{-# LANGUAGE AllowAmbiguousTypes #-}++-- |+-- Module      : Amazonka.Env.Hooks+-- Copyright   : (c) 2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : highly experimental+-- Portability : non-portable (GHC extensions)+--+-- Hooks carried within an 'Env', allowing ad-hoc injection of+-- different behaviour during Amazonka's request/response cycle.+-- Hooks are currently experimental, but Amazonka uses the 'Hooks' API+-- to implement its default logging, and you can add your own+-- behaviour here as well. Some examples of things hooks can do:+--+-- * Log all requests Amazonka makes to a separate log, in order to+--   audit which IAM permissions your program actually needs+--   (see 'requestHook');+--+--   @+--   {-# LANGAUGE OverloadedLabels #-}+--   import Amazonka+--   import Amazonka.Env.Hooks+--   import Data.Generics.Labels ()+--+--   main :: IO ()+--   main = do+--     env <- newEnv discover+--       \<&\> #hooks %~ 'requestHook' ('addAWSRequestHook' $ \\_env req -> req <$ logRequest req)+--     ...+--+--   logRequest :: AWSRequest a => a -> IO ()+--   logRequest = ...+--   @+--+-- * Inject a [Trace ID for AWS X-Ray](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader),+--   into each request before it is signed and sent+--   (see 'configuredRequestHook'); and+--+--   @+--   {-# LANGAUGE OverloadedLabels #-}+--   import Amazonka+--   import Amazonka.Env.Hooks+--   import Data.Generics.Labels ()+--+--   main :: IO ()+--   main = do+--     env <- newEnv discover+--       \<&\> #hooks %~ 'configuredRequestHook' ('addHook' $ \\_env req -> req & #headers %~ addXRayIdHeader)+--     ...+--+--   -- The actual header would normally come from whatever calls into your program,+--   -- or you would randomly generate one yourself (hooks run in 'IO').+--   addXRayIdHeader :: ['Network.HTTP.Types.Header'] -> ['Network.HTTP.Types.Header']+--   addXRayIdHeader = ...+--   @+--+-- * Selectively silence certain expected errors, such as DynamoDB's+--   @ConditionalCheckFailedException@ ('errorHook' and 'silenceError')+--+--   @+--   {-# LANGAUGE OverloadedLabels #-}+--   import Amazonka+--   import Amazonka.Env.Hooks+--   import qualified Amazonka.DynamoDB as DynamoDB+--   import Data.Generics.Labels ()+--+--   main :: IO ()+--   main = do+--     env <- newEnv discover+--     putItemResponse <- runResourceT $+--       send+--         (env & #hooks %~ 'errorHook' ('silenceError' DynamoDB._ConditionalCheckFailedException))+--         (DynamoDB.newPutItem ...)+--     ...+--   @+--+-- Most functions with names ending in @Hook@ ('requestHook', etc.)+-- are intended for use with lenses: partially apply them to get a+-- function @'Hook' a -> 'Hook' a@ that can go on the RHS of @(%~)@+-- (the lens modify function). You then use functions like+-- 'addHookFor' to selectively extend the hooks used at any particular+-- time.+--+-- Names ending in @_@ ('Hook_', 'addHookFor_', etc.) concern hooks+-- that return @()@ instead of the hook's input type. These hooks+-- respond to some event but lack the ability to change Amazonka's+-- behaviour; either because it is unsafe to do so, or because it is+-- difficult to do anything meaningful with the updated value.+--+-- The request/response flow for a standard 'Amazonka.send' looks like+-- this:+--+-- @+--     send (req :: 'AWSRequest' a => a)+--                  |+--                  V+--         Run Hook: request+--                  |+--                  V+-- Amazonka: configure req into "Request a"+--  (Amazonka-specific HTTP request type)+--                  |+--                  V+--     Run Hook: configuredRequest+--                  |+--                  V+-- Amazonka: sign request, turn into standard+--     Network.HTTP.Client.'Network.HTTP.Client.Request'+--                  |+--                  +-<---------------------------------.+--                  V                                   |+--     Run Hook: signedRequest                          |+--                  |                                   |+--                  V                                   |+--     Run Hook: clientRequest                          |+--                  |                                   |+--                  V                                   |+--     Amazonka: send request to AWS           Run Hook: requestRetry+--                  |                                   ^+--                  V                                   |+--     Run Hook: clientResponse                         |+--                  |                                   |+--                  V                                   |+--     Run Hook: rawResponseBody                        |+--                  |                                   |+--                  V                                   |+--     Amazonka: was error? ------------------.         |+--                  |            Yes          |         |+--                  |                         V         |+--                  | No               Run Hook: error  |+--                  |                    ('NotFinal')     |+--                  |                         |         |+--                  +-<-----------------------\'         |+--                  V                                   |+--     Amazonka: should retry? -------------------------\'+--                  |            Yes+--                  | No+--                  V+--     Amazonka: was error? ------------------.+--                  |            Yes          |+--                  |                         V+--                  | No                      |+--                  |                         |+--     Run Hook: response              Run Hook: error+--                  |                     ('Final')+--                  |                         |+--                  V                         |+--     Amazonka: parse response               |+--                  |                         |+--                  +-<-----------------------\'+--                  V+--     Amazonka: return result+-- @+module Amazonka.Env.Hooks+  ( Hook,+    Hook_,+    Hooks (..),+    Finality (..),++    -- * Updating members of 'Hooks'+    requestHook,+    waitHook,+    configuredRequestHook,+    signedRequestHook,+    clientRequestHook,+    clientResponseHook,+    rawResponseBodyHook,+    requestRetryHook,+    awaitRetryHook,+    responseHook,+    errorHook,++    -- * Functions to use with the ones above+    noHook,+    noHook_,+    addHook,+    addHook_,+    addAWSRequestHook,+    addAWSRequestHook_,+    addHookFor,+    addHookFor_,+    removeHooksFor,+    removeHooksFor_,++    -- ** Specialty combinators+    silenceError,++    -- * Building 'Hooks'+    addLoggingHooks,+    noHooks,+  )+where++import {-# SOURCE #-} Amazonka.Env (Env' (..))+import Amazonka.Logger (build, logDebug, logError, logTrace)+import Amazonka.Prelude hiding (error)+import Amazonka.Types+  ( AWSRequest,+    AWSResponse,+    ClientRequest,+    ClientResponse,+    Error,+    Request,+    Signed (..),+  )+import Amazonka.Waiter (Accept, Wait (..))+import Control.Lens (Getting, has)+import qualified Control.Retry as Retry+import Data.List (intersperse)+import Data.Monoid (Any)+import Data.Typeable (Typeable, eqT, (:~:) (..))++-- | A hook that returns an updated version of its arguments.+type Hook a = forall withAuth. Env' withAuth -> a -> IO a++-- | A hook that cannot return an updated version of its argument.+type Hook_ a = forall withAuth. Env' withAuth -> a -> IO ()++-- | Indicates whether an error hook is potentially going to be+-- retried.+--+-- /See:/ 'error'+data Finality = NotFinal | Final+  deriving stock (Bounded, Enum, Eq, Ord, Show, Generic)++data Hooks = Hooks+  { -- | Called at the start of request processing, before the request+    -- is configured. This is always the first hook that runs, and+    -- argument is usually a request record type like @amazonka-s3@'s+    -- @GetObjectRequest@.+    request :: forall a. (AWSRequest a, Typeable a) => Hook a,+    -- | Called after the request has been configured into an abstract+    -- HTTP request, but before it is converted to a signed+    -- @Network.HTTP.Client.'Network.HTTP.Client.Request'@.+    --+    -- If you want to add additional headers (e.g., a+    -- [Trace ID for AWS X-Ray](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader)),+    -- do it with this hook.+    configuredRequest :: forall a. (AWSRequest a, Typeable a) => Hook (Request a),+    -- | Called at the start of waiter processing, just after the+    -- request is configured.+    wait :: forall a. (AWSRequest a, Typeable a) => Hook (Wait a),+    -- | Called just after a request is signed, containing signature+    -- metadata and a+    -- @Network.HTTP.Client.'Network.HTTP.Client.Request'@.+    signedRequest :: forall a. (AWSRequest a, Typeable a) => Hook_ (Signed a),+    -- | Called on a+    -- @Network.HTTP.Client.'Network.HTTP.Client.Request'@, just+    -- before it is sent. While you can retrieve a 'ClientRequest'+    -- from the 'signedRequest' hook, this hook captures unsigned+    -- requests too.+    --+    -- Changing the contents of a signed request is highly likely to+    -- break its signature.+    clientRequest :: Hook ClientRequest,+    -- | Called on the raw+    -- @Network.HTTP.Client.'Network.HTTP.Client.Response'@, as soon+    -- as it comes back from the HTTP client. The body is replaced+    -- with @()@ to prevent its accidental consumption by hooks.+    clientResponse ::+      forall a.+      (AWSRequest a, Typeable a) =>+      Hook_ (Request a, ClientResponse ()),+    -- | Called on the raw response body, after it has been sunk from+    -- the @Network.HTTP.Client.'Network.HTTP.Client.Response'@.+    rawResponseBody :: Hook ByteStringLazy,+    -- | Called when Amazonka decides to retry a failed request. The+    -- 'Text' argument is an error code like @"http_error"@,+    -- @"request_throttled_exception"@. Check the retry check+    -- function for your particular 'Service', usually found somewhere+    -- like @Amazonka.S3.Types.defaultService@.+    requestRetry ::+      forall a.+      (AWSRequest a, Typeable a) =>+      Hook_ (Request a, Text, Retry.RetryStatus),+    -- | Called when Amazonka decides to retry a request while+    -- resolving an 'Amazonka.await' operation.+    awaitRetry ::+      forall a.+      (AWSRequest a, Typeable a) =>+      Hook_ (Request a, Wait a, Accept, Retry.RetryStatus),+    -- | Called when a response from AWS is successfully+    -- deserialised. Because the 'AWSResponse' type family is not+    -- injective, we include the original request.+    response ::+      forall a.+      (AWSRequest a, Typeable a) =>+      Hook_ (Request a, ClientResponse (AWSResponse a)),+    -- | Called whenever an AWS request returns an 'Error', even when+    -- the corresponding request is retried.+    --+    -- On the final error after all retries, this hook will be called+    -- twice: once with @NotFinal@ and once with @Final@. This+    -- behavior may change in a future version.+    error ::+      forall a.+      (AWSRequest a, Typeable a) =>+      Hook_ (Finality, Request a, Error)+  }++{-# INLINE requestHook #-}+requestHook ::+  (forall a. (AWSRequest a, Typeable a) => Hook a -> Hook a) ->+  Hooks ->+  Hooks+requestHook f hooks@Hooks {request} =+  hooks {request = f request}++{-# INLINE waitHook #-}+waitHook ::+  (forall a. (AWSRequest a, Typeable a) => Hook (Wait a) -> Hook (Wait a)) ->+  Hooks ->+  Hooks+waitHook f hooks@Hooks {wait} =+  hooks {wait = f wait}++{-# INLINE configuredRequestHook #-}+configuredRequestHook ::+  ( forall a.+    (AWSRequest a, Typeable a) =>+    Hook (Request a) ->+    Hook (Request a)+  ) ->+  Hooks ->+  Hooks+configuredRequestHook f hooks@Hooks {configuredRequest} =+  hooks {configuredRequest = f configuredRequest}++{-# INLINE signedRequestHook #-}+signedRequestHook ::+  ( forall a.+    (AWSRequest a, Typeable a) =>+    Hook_ (Signed a) ->+    Hook_ (Signed a)+  ) ->+  Hooks ->+  Hooks+signedRequestHook f hooks@Hooks {signedRequest} =+  hooks {signedRequest = f signedRequest}++{-# INLINE clientRequestHook #-}+clientRequestHook ::+  (Hook ClientRequest -> Hook ClientRequest) ->+  Hooks ->+  Hooks+clientRequestHook f hooks@Hooks {clientRequest} =+  hooks {clientRequest = f clientRequest}++{-# INLINE clientResponseHook #-}+clientResponseHook ::+  ( forall a.+    (AWSRequest a, Typeable a) =>+    Hook_ (Request a, ClientResponse ()) ->+    Hook_ (Request a, ClientResponse ())+  ) ->+  Hooks ->+  Hooks+clientResponseHook f hooks@Hooks {clientResponse} =+  hooks {clientResponse = f clientResponse}++{-# INLINE rawResponseBodyHook #-}+rawResponseBodyHook ::+  (Hook ByteStringLazy -> Hook ByteStringLazy) ->+  Hooks ->+  Hooks+rawResponseBodyHook f hooks@Hooks {rawResponseBody} =+  hooks {rawResponseBody = f rawResponseBody}++{-# INLINE requestRetryHook #-}+requestRetryHook ::+  ( forall a.+    (AWSRequest a, Typeable a) =>+    Hook_ (Request a, Text, Retry.RetryStatus) ->+    Hook_ (Request a, Text, Retry.RetryStatus)+  ) ->+  Hooks ->+  Hooks+requestRetryHook f hooks@Hooks {requestRetry} =+  hooks {requestRetry = f requestRetry}++{-# INLINE awaitRetryHook #-}+awaitRetryHook ::+  ( forall a.+    (AWSRequest a, Typeable a) =>+    Hook_ (Request a, Wait a, Accept, Retry.RetryStatus) ->+    Hook_ (Request a, Wait a, Accept, Retry.RetryStatus)+  ) ->+  Hooks ->+  Hooks+awaitRetryHook f hooks@Hooks {awaitRetry} =+  hooks {awaitRetry = f awaitRetry}++{-# INLINE responseHook #-}+responseHook ::+  ( forall a.+    (AWSRequest a, Typeable a) =>+    Hook_ (Request a, ClientResponse (AWSResponse a)) ->+    Hook_ (Request a, ClientResponse (AWSResponse a))+  ) ->+  Hooks ->+  Hooks+responseHook f hooks@Hooks {response} =+  hooks {response = f response}++{-# INLINE errorHook #-}+errorHook ::+  ( forall a.+    (AWSRequest a, Typeable a) =>+    Hook_ (Finality, Request a, Error) ->+    Hook_ (Finality, Request a, Error)+  ) ->+  Hooks ->+  Hooks+errorHook f hooks@Hooks {error} =+  hooks {error = f error}++-- | Turn a @'Hook' a@ into another @'Hook' a@ that does nothing.+--+-- -- Example: remove all request hooks:+-- @+-- requestHook noHook :: Hooks -> Hooks+-- @+noHook :: Hook a -> Hook a+noHook _ _ = pure++-- | Turn a @'Hook_' a@ into another @'Hook_' a@ that does nothing.+--+-- @+-- -- Example: Remove all response hooks:+-- responseHook noHook_ :: Hooks -> Hooks+-- @+noHook_ :: Hook_ a -> Hook_ a+noHook_ _ _ _ = pure ()++-- | Unconditionally add a @'Hook' a@ to the chain of hooks. If you+-- need to do something with specific request types, you want+-- 'addHookFor', instead.+addHook :: Typeable a => Hook a -> Hook a -> Hook a+addHook newHook oldHook env = oldHook env >=> newHook env++-- | Unconditionally add a @'Hook_' a@ to the chain of hooks. If you+-- need to do something with specific request types, you want+-- 'addHookFor_', instead.+addHook_ :: Typeable a => Hook_ a -> Hook_ a -> Hook_ a+addHook_ newHook oldHook env a = oldHook env a *> newHook env a++-- | Like 'addHook', adds an unconditional hook, but it also captures+-- the @'AWSRequest' a@ constraint. Useful for handling every AWS+-- request type in a generic way.+addAWSRequestHook :: (AWSRequest a, Typeable a) => Hook a -> Hook a -> Hook a+addAWSRequestHook = addHook++-- | 'addAWSRequestHook_' is 'addAWSRequestHook' but for 'Hook_'s.+addAWSRequestHook_ :: (AWSRequest a, Typeable a) => Hook_ a -> Hook_ a -> Hook_ a+addAWSRequestHook_ = addHook_++-- | @addHookFor \@a newHook oldHook@ When @a@ and @b@ are the same+-- type, run the given 'Hook a' after all others, otherwise only run+-- the existing hooks.+--+-- @+-- -- Example: Run @getObjectRequestHook@ on anything that is a @GetObjectRequest@:+-- requestHook (addHookFor @GetObjectRequest getObjectRequestHook) :: Hooks -> Hooks+-- @+addHookFor ::+  forall a b. (Typeable a, Typeable b) => Hook a -> Hook b -> Hook b+addHookFor newHook oldHook env =+  oldHook env >=> case eqT @a @b of+    Just Refl -> newHook env+    Nothing -> pure++-- | When @a@ and @b@ are the same type, run the given 'Hook_ a' after+-- all other hooks have run.+--+-- @+-- -- Example: Run @aSignedRequestHook@ on anything that is a @Signed GetObjectRequest@:+-- requestHook (addHookFor_ @(Signed GetObjectRequest) aSignedRequestHook) :: Hooks -> Hooks+-- @+addHookFor_ ::+  forall a b. (Typeable a, Typeable b) => Hook_ a -> Hook_ b -> Hook_ b+addHookFor_ newHook oldHook env a = do+  oldHook env a+  case eqT @a @b of+    Just Refl -> newHook env a+    Nothing -> pure ()++-- | When @a@ and @b@ are the same type, do not call any more hooks.+--+-- @+-- -- Example: Prevent any request hooks from running against a @PutObjectRequest@:+-- requestHook (removeHooksFor @PutObjectRequest) :: Hooks -> Hooks+-- @+removeHooksFor :: forall a b. (Typeable a, Typeable b) => Hook b -> Hook b+removeHooksFor oldHook env = case eqT @a @b of+  Just Refl -> pure+  Nothing -> oldHook env++-- | When @a@ and @b@ are the same type, do not call any more hooks.+--+-- @+-- -- Example: Prevent any error hooks from running against errors caused by a @PutObjectRequest@:+-- errorHook (removeHooksFor @(Finality, Request PutObjectRequest, Error)) :: Hooks -> Hooks+-- @+removeHooksFor_ :: forall a b. (Typeable a, Typeable b) => Hook_ b -> Hook_ b+removeHooksFor_ oldHook env a = case eqT @a @b of+  Just Refl -> pure ()+  Nothing -> oldHook env a++-- | Run the wrapped hook unless the given 'Fold' or 'Traversal'+-- matches the error. You will probably want to use this with the+-- error matchers defined by each service binding, allowing you to+-- selectively silence specific errors:+--+-- @+-- -- Assuming `env :: Amazonka.Env` and `putRequest :: DynamoDB.PutRequest`,+-- -- this silences a single type of error for a single call:+-- send (env & #hooks %~ errorHook (silenceError DynamoDB._ConditionalCheckFailedException))+-- @+--+-- @+-- 'silenceError' :: Getter Error e     -> 'Hook_' ('Finality', Request a, Error) -> 'Hook_' ('Finality', Request a, Error)+-- 'silenceError' :: Fold Error e       -> 'Hook_' ('Finality', Request a, Error) -> 'Hook_' ('Finality', Request a, Error)+-- 'silenceError' :: Iso' Error e       -> 'Hook_' ('Finality', Request a, Error) -> 'Hook_' ('Finality', Request a, Error)+-- 'silenceError' :: Lens' Error e      -> 'Hook_' ('Finality', Request a, Error) -> 'Hook_' ('Finality', Request a, Error)+-- 'silenceError' :: Traversal' Error e -> 'Hook_' ('Finality', Request a, Error) -> 'Hook_' ('Finality', Request a, Error)+-- @+silenceError ::+  Getting Any Error e ->+  Hook_ (Finality, Request a, Error) ->+  Hook_ (Finality, Request a, Error)+silenceError g oldHook env t@(_, _, err) =+  if has g err then pure () else oldHook env t++-- | Add default logging hooks. The default 'Env'' from+-- 'Amazonka.Env.newEnv' already has logging hooks installed, so you+-- probably only want this if you are building your own 'Hooks' from+-- scratch.+addLoggingHooks :: Hooks -> Hooks+addLoggingHooks+  hooks@Hooks+    { signedRequest,+      clientRequest,+      clientResponse,+      rawResponseBody,+      requestRetry,+      awaitRetry,+      error+    } =+    hooks+      { signedRequest = \env@Env {logger} s@Signed {signedMeta} -> do+          signedRequest env s+          logTrace logger signedMeta,+        clientRequest = \env@Env {logger} rq -> do+          rq' <- clientRequest env rq+          rq' <$ logDebug logger rq',+        clientResponse = \env@Env {logger} t@(_, rs) -> do+          clientResponse env t+          logDebug logger rs,+        rawResponseBody = \env@Env {logger} body -> do+          body' <- rawResponseBody env body+          body' <$ logTrace logger ("[Raw Response Body] {\n" <> body' <> "\n}"),+        requestRetry = \env@Env {logger} t@(_, name, retryStatus) -> do+          requestRetry env t+          logDebug logger . munwords $+            [ "[Retry " <> build name <> "]",+              "after",+              build (Retry.rsIterNumber retryStatus + 1),+              "attempt(s)."+            ],+        awaitRetry = \env@Env {logger} t@(_, Wait {name}, accept, retryStatus) -> do+          awaitRetry env t+          logDebug logger . munwords $+            [ "[Await " <> build name <> "]",+              build accept,+              "after",+              build (Retry.rsIterNumber retryStatus + 1),+              "attempts."+            ],+        error = \env@Env {logger} t@(finality, _, err) -> do+          error env t+          case finality of+            NotFinal -> logDebug logger err+            Final -> logError logger err+      }+    where+      munwords = mconcat . intersperse " "++-- | Empty 'Hooks' structure which returns everything unmodified.+noHooks :: Hooks+noHooks =+  Hooks+    { request = const pure,+      configuredRequest = const pure,+      wait = const pure,+      signedRequest = \_ _ -> pure (),+      clientRequest = const pure,+      clientResponse = \_ _ -> pure (),+      rawResponseBody = const pure,+      requestRetry = \_ _ -> pure (),+      awaitRetry = \_ _ -> pure (),+      response = \_ _ -> pure (),+      error = \_ _ -> pure ()+    }
+ src/Amazonka/Env/Hooks.hs-boot view
@@ -0,0 +1,3 @@+module Amazonka.Env.Hooks where++data Hooks
+ src/Amazonka/HTTP.hs view
@@ -0,0 +1,177 @@+-- |+-- Module      : Amazonka.HTTP+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+module Amazonka.HTTP+  ( retryRequest,+    awaitRequest,+    httpRequest,+    configureRequest,+    retryService,+    retryStream,+  )+where++import Amazonka.Core.Lens.Internal (to, (^?), _Just)+import Amazonka.Data.Body (isStreaming)+import Amazonka.Env hiding (auth)+import Amazonka.Env.Hooks (Finality (..))+import qualified Amazonka.Env.Hooks as Hooks+import Amazonka.Prelude+import Amazonka.Types+import Amazonka.Waiter+import Control.Exception as Exception+import Control.Monad.Trans.Resource (liftResourceT, transResourceT)+import qualified Control.Retry as Retry+import Data.Foldable (traverse_)+import qualified Data.Time as Time+import Data.Typeable (Typeable)+import qualified Network.HTTP.Conduit as Client.Conduit++retryRequest ::+  forall m a withAuth.+  ( MonadResource m,+    AWSRequest a,+    Typeable a,+    Typeable (AWSResponse a),+    Foldable withAuth+  ) =>+  Env' withAuth ->+  a ->+  m (Either Error (ClientResponse (AWSResponse a)))+retryRequest env@Env {hooks} rq = do+  rq' <- liftIO $ Hooks.request hooks env rq+  cfgRq <- configureRequest env rq'++  let attempt _ = httpRequest env cfgRq+      policy = retryStream cfgRq <> retryService (service cfgRq)+      Request+        { service = Service {retry = Exponential {check = serviceRetryCheck}}+        } = cfgRq++      shouldRetry :: Retry.RetryStatus -> Either Error b -> m Bool+      shouldRetry s =+        liftIO . \case+          Left r+            | Just True <- r ^? transportErr ->+                True <$ Hooks.requestRetry hooks env (cfgRq, "http_error", s)+            | Just name <- r ^? serviceErr ->+                True <$ Hooks.requestRetry hooks env (cfgRq, name, s)+          _other -> pure False+        where+          transportErr =+            _TransportError . to (retryCheck env (Retry.rsIterNumber s))++          serviceErr =+            _ServiceError . to serviceRetryCheck . _Just++  Retry.retrying policy shouldRetry attempt >>= \case+    Left e -> Left e <$ liftIO (Hooks.error hooks env (Final, cfgRq, e))+    Right a -> pure $ Right a++awaitRequest ::+  ( MonadResource m,+    AWSRequest a,+    Typeable a,+    Foldable withAuth+  ) =>+  Env' withAuth ->+  Wait a ->+  a ->+  m (Either Error Accept)+awaitRequest env@Env {hooks} w rq = do+  rq' <- liftIO $ Hooks.request hooks env rq+  cfgRq <- configureRequest env rq'+  w'@Wait {..} <- liftIO $ Hooks.wait hooks env w++  let handleResult res = (fromMaybe AcceptRetry $ accept w' cfgRq res, res)+      attempt _ = handleResult <$> httpRequest env cfgRq+      policy =+        Retry.limitRetries attempts+          <> Retry.constantDelay (toMicroseconds delay)++      check retryStatus (a, _) = do+        liftIO $ Hooks.awaitRetry hooks env (cfgRq, w', a, retryStatus)+        pure $ case a of+          AcceptSuccess -> False+          AcceptFailure -> False+          AcceptRetry -> True++  Retry.retrying policy check attempt >>= \case+    (AcceptSuccess, _) -> pure $ Right AcceptSuccess+    (_, Left e) -> Left e <$ liftIO (Hooks.error hooks env (Final, cfgRq, e))+    (a, _) -> pure $ Right a++-- | Make a one-shot request to AWS, using a configured 'Request'+-- (which contains the 'Service', plus any overrides).+httpRequest ::+  ( MonadResource m,+    AWSRequest a,+    Typeable a,+    Foldable withAuth+  ) =>+  Env' withAuth ->+  Request a ->+  m (Either Error (ClientResponse (AWSResponse a)))+httpRequest env@Env {hooks, manager, region} cfgRq =+  liftResourceT (transResourceT (`Exception.catches` handlers) go)+  where+    go = do+      time <- liftIO Time.getCurrentTime++      clientRq :: ClientRequest <-+        liftIO . Hooks.clientRequest hooks env =<< case authMaybe env of+          Nothing -> pure $! requestUnsigned cfgRq region+          Just auth -> withAuth auth $ \a -> do+            let s@(Signed _ rq) = requestSign cfgRq a region time+            liftIO $ Hooks.signedRequest hooks env s+            pure $! rq++      rs <- Client.Conduit.http clientRq manager+      liftIO $ Hooks.clientResponse hooks env (cfgRq, void rs)+      parsedRs <-+        response+          (Hooks.rawResponseBody hooks env)+          (service cfgRq)+          (proxy cfgRq)+          rs+      traverse_ (liftIO . Hooks.response hooks env . (cfgRq,)) parsedRs+      pure parsedRs++    handlers :: [Handler (Either Error b)]+    handlers =+      [ Handler err,+        Handler $ err . TransportError+      ]+      where+        err e = Left e <$ Hooks.error hooks env (NotFinal, cfgRq, e)++    proxy :: Request a -> Proxy a+    proxy _ = Proxy++-- Configures an AWS request `a` into its `Request a` form, applying+-- service overrides from `env` and running hooks on the configured+-- (Request a).+configureRequest ::+  (AWSRequest a, Typeable a, MonadIO m) => Env' withAuth -> a -> m (Request a)+configureRequest env@Env {overrides, hooks} =+  liftIO+    . Hooks.configuredRequest hooks env+    . request overrides++retryStream :: Request a -> Retry.RetryPolicy+retryStream Request {body} =+  Retry.RetryPolicyM $ \_ -> pure $ if isStreaming body then Nothing else Just 0++retryService :: Service -> Retry.RetryPolicy+retryService Service {retry = Exponential {..}} =+  Retry.limitRetries attempts <> Retry.RetryPolicyM (pure . delay)+  where+    delay (Retry.rsIterNumber -> n)+      | n >= 0 = Just $ truncate (grow * 1000000)+      | otherwise = Nothing+      where+        grow = base * (fromIntegral growth ^^ (n - 1))
+ src/Amazonka/Lens.hs view
@@ -0,0 +1,60 @@+-- |+-- Module      : Amazonka.Lens+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Re-export lenses and other optics for types in @amazonka@ and+-- @amazonka-core@. You will probably find record updates,+-- [generic-lens](https://hackage.haskell.org/package/generic-lens),+-- [generic-optics](https://hackage.haskell.org/package/generic-optics),+-- or (GHC >=9.2) @-XOverloadedRecordDot@ more ergonomic than these.+module Amazonka.Lens+  ( -- * Amazonka.Auth.SSO++    -- ** CachedAccessToken+    cachedAccessToken_startUrl,+    cachedAccessToken_region,+    cachedAccessToken_accessToken,+    cachedAccessToken_expiresAt,++    -- * Amazonka.EC2.Metadata++    -- ** IdentityDocument+    identityDocument_devpayProductCodes,+    identityDocument_billingProducts,+    identityDocument_version,+    identityDocument_privateIp,+    identityDocument_availabilityZone,+    identityDocument_region,+    identityDocument_instanceId,+    identityDocument_instanceType,+    identityDocument_accountId,+    identityDocument_imageId,+    identityDocument_kernelId,+    identityDocument_ramdiskId,+    identityDocument_architecture,+    identityDocument_pendingTime,++    -- * Amazonka.Env++    -- ** Env'+    env_region,+    env_logger,+    env_hooks,+    env_retryCheck,+    env_overrides,+    env_manager,+    env_auth,++    -- * Amazonka.Core.Lens+    module Amazonka.Core.Lens,+  )+where++import Amazonka.Auth.SSO+import Amazonka.Core.Lens+import Amazonka.EC2.Metadata+import Amazonka.Env
+ src/Amazonka/Logger.hs view
@@ -0,0 +1,85 @@+-- |+-- Module      : Amazonka.Logger+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- Types and functions for constructing loggers and emitting log messages.+module Amazonka.Logger+  ( -- * Constructing a Logger+    Logger,+    newLogger,++    -- * Levels+    LogLevel (..),+    logError,+    logInfo,+    logDebug,+    logTrace,++    -- * Building Messages+    ToLog (..),+    buildLines,+  )+where++import Amazonka.Data+import Amazonka.Prelude+import qualified Control.Monad as Monad+import qualified Data.ByteString.Builder as Build+import qualified System.IO as IO++-- | A logging function called by various default hooks to log+-- informational and debug messages.+type Logger = LogLevel -> ByteStringBuilder -> IO ()++-- | This is a primitive logger which can be used to log builds to a 'Handle'.+--+-- /Note:/ A more sophisticated logging library such as+-- <http://hackage.haskell.org/package/tinylog tinylog> or+-- <http://hackage.haskell.org/package/fast-logger fast-logger>+-- should be used in production code.+newLogger :: MonadIO m => LogLevel -> IO.Handle -> m Logger+newLogger x hd =+  liftIO $ do+    IO.hSetBuffering hd IO.LineBuffering++    pure $ \y b ->+      Monad.when (x >= y) $+        Build.hPutBuilder hd (b <> "\n")++data LogLevel+  = -- | Info messages supplied by the user - this level is not emitted by the library.+    Info+  | -- | Error messages only.+    Error+  | -- | Useful debug information + info + error levels.+    Debug+  | -- | Includes potentially sensitive signing metadata, and non-streaming response bodies.+    Trace+  deriving stock (Eq, Ord, Enum, Show, Generic)++instance FromText LogLevel where+  fromText = \case+    "info" -> pure Info+    "error" -> pure Error+    "debug" -> pure Debug+    "trace" -> pure Trace+    other -> Left ("Failure parsing LogLevel from " ++ show other)++instance ToText LogLevel where+  toText = \case+    Info -> "info"+    Error -> "error"+    Debug -> "debug"+    Trace -> "trace"++instance ToByteString LogLevel++logError, logInfo, logDebug, logTrace :: (MonadIO m, ToLog a) => Logger -> a -> m ()+logError f = liftIO . f Error . build+logInfo f = liftIO . f Info . build+logDebug f = liftIO . f Debug . build+logTrace f = liftIO . f Trace . build
+ src/Amazonka/Presign.hs view
@@ -0,0 +1,105 @@+-- |+-- Module      : Amazonka.Presign+-- Copyright   : (c) 2013-2023 Brendan Hay+-- License     : Mozilla Public License, v. 2.0.+-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>+-- Stability   : provisional+-- Portability : non-portable (GHC extensions)+--+-- It is intended for use directly with 'Amazonka.Auth.Auth' when only+-- presigning and no other AWS actions are required.+-- See 'Amazonka.Auth.withAuth' to extract an 'AuthEnv' from an 'Auth'.++{-# LANGUAGE BangPatterns #-}++module Amazonka.Presign where++import Amazonka.Data+import Amazonka.Prelude+import Amazonka.Request (clientRequestURL)+import Amazonka.Types hiding (presign)+import qualified Network.HTTP.Types as HTTP++-- | Presign an URL that is valid from the specified time until the+-- number of seconds expiry has elapsed.+--+-- /See:/ 'presign', 'presignWith'+presignURL ::+  (AWSRequest a) =>+  AuthEnv ->+  Region ->+  -- | Signing time.+  UTCTime ->+  -- | Expiry time.+  Seconds ->+  -- | Request to presign.+  a ->+  ByteString+presignURL a r e ts = clientRequestURL . presign a r e ts++-- | Presign an HTTP request that is valid from the specified time until the+-- number of seconds expiry has elapsed.+--+-- /See:/ 'presignWith', 'presignWithHeaders'+presign ::+  (AWSRequest a) =>+  AuthEnv ->+  Region ->+  -- | Signing time.+  UTCTime ->+  -- | Expiry time.+  Seconds ->+  -- | Request to presign.+  a ->+  ClientRequest+presign =+  presignWith id++-- | A variant of 'presign' that allows modifying the default 'Service'+-- definition used to configure the request.+--+-- /See:/ 'presignWithHeaders'+presignWith ::+  (AWSRequest a) =>+  -- | Modify the default service configuration.+  (Service -> Service) ->+  AuthEnv ->+  Region ->+  -- | Signing time.+  UTCTime ->+  -- | Expiry time.+  Seconds ->+  -- | Request to presign.+  a ->+  ClientRequest+presignWith = presignWithHeaders defaultHeaders++-- | Modification to the headers that is applied by default (in 'presignWith');+-- removes the "Expect" header which is added to every 'PutObject'.+defaultHeaders :: [HTTP.Header] -> [HTTP.Header]+defaultHeaders = filter ((/= hExpect) . fst)++-- | A variant of 'presign' that allows modifying the default 'Headers'+-- and the default 'Service' definition used to configure the request.+presignWithHeaders ::+  forall a.+  (AWSRequest a) =>+  -- | Modify the default headers.+  ([Header] -> [Header]) ->+  -- | Modify the default service configuration.+  (Service -> Service) ->+  AuthEnv ->+  Region ->+  -- | Signing time.+  UTCTime ->+  -- | Expiry time.+  Seconds ->+  -- | Request to presign.+  a ->+  ClientRequest+presignWithHeaders f g ae r ts ex x =+  let rq@Request {headers} = request g x+      rq' :: Request a+      rq' = rq {headers = f headers}+      !creq = signedRequest $ requestPresign ex rq' ae r ts+   in creq
+ src/Amazonka/Send.hs view
@@ -0,0 +1,170 @@+module Amazonka.Send+  ( send,+    sendEither,+    paginate,+    paginateEither,+    await,+    awaitEither,+    sendUnsigned,+    sendUnsignedEither,+  )+where++import Amazonka.Core (AWSPager, AWSRequest, AWSResponse, Error)+import Amazonka.Env (Env, Env' (..))+import qualified Amazonka.HTTP as HTTP+import qualified Amazonka.Pager as Pager+import Amazonka.Prelude+import qualified Amazonka.Waiter as Waiter+import qualified Control.Exception as Exception+import Data.Conduit (ConduitM)+import qualified Data.Conduit as Conduit+import Data.Typeable (Typeable)+import qualified Network.HTTP.Client as Client++-- | Send a request, returning the associated response if successful.+--+-- See 'send'.+sendEither ::+  ( MonadResource m,+    AWSRequest a,+    Typeable a,+    Typeable (AWSResponse a)+  ) =>+  Env ->+  a ->+  m (Either Error (AWSResponse a))+sendEither env =+  fmap (second Client.responseBody) . HTTP.retryRequest env++-- | Send a request, returning the associated response if successful.+--+-- Errors are thrown in 'IO'.+--+-- See 'sendEither'.+send ::+  ( MonadResource m,+    AWSRequest a,+    Typeable a,+    Typeable (AWSResponse a)+  ) =>+  Env ->+  a ->+  m (AWSResponse a)+send env =+  sendEither env >=> hoistEither++-- | Make a request without signing it. You will almost never need to+-- do this, but some authentication methods+-- (e.g. @sts:AssumeRoleWithWebIdentity@ and @sso:GetRoleCredentials@)+-- require you to exchange a token using an unsigned+-- request. Amazonka's support for these authentication methods calls+-- 'sendUnsigned', and we re-export these functions in case you need+-- to support similar authentication methods in your code.+--+-- See 'sendUnsigned'.+sendUnsignedEither ::+  ( MonadResource m,+    AWSRequest a,+    Typeable a,+    Typeable (AWSResponse a)+  ) =>+  Env' withAuth ->+  a ->+  m (Either Error (AWSResponse a))+sendUnsignedEither env =+  fmap (second Client.responseBody) . HTTP.retryRequest (env {auth = Proxy})++-- | Make an unsigned request, returning the associated response if successful.+--+-- Errors are thrown in 'IO'.+--+-- See 'sendUnsignedEither'.+sendUnsigned ::+  ( MonadResource m,+    AWSRequest a,+    Typeable a,+    Typeable (AWSResponse a)+  ) =>+  Env' withAuth ->+  a ->+  m (AWSResponse a)+sendUnsigned env =+  sendUnsignedEither env >=> hoistEither++-- | Repeatedly send a request, automatically setting markers and performing pagination.+--+-- Exits on the first encountered error.+--+-- See 'paginate'.+paginateEither ::+  ( MonadResource m,+    AWSPager a,+    Typeable a,+    Typeable (AWSResponse a)+  ) =>+  Env ->+  a ->+  ConduitM () (AWSResponse a) m (Either Error ())+paginateEither env = go+  where+    go rq =+      lift (sendEither env rq) >>= \case+        Left err -> pure (Left err)+        Right rs -> do+          Conduit.yield rs+          maybe (pure (Right ())) go (Pager.page rq rs)++-- | Repeatedly send a request, automatically setting markers and performing pagination.+-- Exits on the first encountered error.+--+-- Errors are thrown in 'IO'.+--+-- See 'paginateEither'.+paginate ::+  ( MonadResource m,+    AWSPager a,+    Typeable a,+    Typeable (AWSResponse a)+  ) =>+  Env ->+  a ->+  ConduitM () (AWSResponse a) m ()+paginate env =+  paginateEither env >=> hoistEither++-- | Poll the API with the supplied request until a specific 'Wait' condition+-- is fulfilled.+--+-- See 'await'.+awaitEither ::+  ( MonadResource m,+    AWSRequest a,+    Typeable a+  ) =>+  Env ->+  Waiter.Wait a ->+  a ->+  m (Either Error Waiter.Accept)+awaitEither = HTTP.awaitRequest++-- | Poll the API with the supplied request until a specific 'Wait' condition+-- is fulfilled.+--+-- Errors are thrown in 'IO'.+--+-- See 'awaitEither'.+await ::+  ( MonadResource m,+    AWSRequest a,+    Typeable a+  ) =>+  Env ->+  Waiter.Wait a ->+  a ->+  m Waiter.Accept+await env wait =+  awaitEither env wait >=> hoistEither++hoistEither :: MonadIO m => Either Error a -> m a+hoistEither = either (liftIO . Exception.throwIO) pure
− src/Control/Monad/Trans/AWS.hs
@@ -1,537 +0,0 @@-{-# LANGUAGE BangPatterns               #-}-{-# LANGUAGE ConstraintKinds            #-}-{-# LANGUAGE FlexibleContexts           #-}-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase                 #-}-{-# LANGUAGE MultiParamTypeClasses      #-}-{-# LANGUAGE RankNTypes                 #-}-{-# LANGUAGE RecordWildCards            #-}-{-# LANGUAGE TypeFamilies               #-}-{-# LANGUAGE UndecidableInstances       #-}--{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}---- |--- Module      : Control.Monad.Trans.AWS--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : provisional--- Portability : non-portable (GHC extensions)------ The 'AWST' transformer provides the environment required to perform AWS--- operations. The transformer is intended to be used directly--- or embedded as a layer within a transformer stack.------ "Network.AWS" contains an 'IO' specialised version of 'AWST' with a typeclass--- to assist in automatically lifting operations.-module Control.Monad.Trans.AWS-    (-    -- * Running AWS Actions-      AWST-    , AWST'-    , runAWST-    , runResourceT-    , AWSConstraint--    -- * Authentication and Environment-    , newEnv-    , Env-    , HasEnv       (..)--    -- ** Credential Discovery-    , Credentials  (..)-    -- $discovery--    -- ** Supported Regions-    , Region       (..)--    -- * Sending Requests-    -- $sending--    , send--    -- ** Pagination-    -- $pagination--    , paginate--    -- ** Waiters-    -- $waiters--    , await--    -- ** Service Configuration-    -- $service--    -- *** Overriding Defaults-    , configure-    , override--    -- *** Scoped Actions-    , reconfigure-    , within-    , once-    , timeout--    -- ** Streaming-    -- $streaming--    -- *** Request Bodies-    , ToHashedBody (..)-    , hashedFile-    , hashedBody--    -- *** Chunked Request Bodies-    , ToBody       (..)-    , ChunkSize    (..)-    , defaultChunkSize-    , chunkedFile-    , unsafeChunkedBody--    -- *** Response Bodies-    , sinkBody--    -- *** File Size and MD5/SHA256-    , getFileSize-    , sinkMD5-    , sinkSHA256--    -- * Presigning Requests-    -- $presigning--    , presignURL-    , presign--    -- * EC2 Instance Metadata-    -- $metadata--    , isEC2-    , dynamic-    , metadata-    , userdata--    , EC2.Dynamic  (..)-    , EC2.Metadata (..)--    -- * Running Asynchronous Actions-    -- $async--    -- * Handling Errors-    -- $errors--    , AsError      (..)-    , AsAuthError  (..)--    , trying-    , catching--    -- * Logging-    -- $logging--    , Logger-    , LogLevel     (..)--    -- ** Constructing a Logger-    , newLogger--    -- ** Endpoints-    , Endpoint-    , setEndpoint--    -- * Re-exported Types-    , module Network.AWS.Types-    , module Network.AWS.Waiter-    , module Network.AWS.Pager-    , RqBody-    , HashedBody-    , ChunkedBody-    , RsBody-    ) where--import           Control.Applicative-import           Control.Monad.Base-import           Control.Monad.Catch-import           Control.Monad.Error.Class    (MonadError (..))-import           Control.Monad.Morph-import           Control.Monad.Reader-import           Control.Monad.State.Class-import           Control.Monad.Trans.Control-import           Control.Monad.Trans.Resource-import           Control.Monad.Writer.Class-import           Data.Conduit                 hiding (await)-import           Data.Conduit.Lazy            (MonadActive (..))-import           Data.IORef-import           Data.Monoid-import           Network.AWS.Auth-import qualified Network.AWS.EC2.Metadata     as EC2-import           Network.AWS.Env-import           Network.AWS.Internal.Body-import           Network.AWS.Internal.HTTP-import           Network.AWS.Internal.Logger-import           Network.AWS.Lens             (catching, throwingM, trying,-                                               view)-import           Network.AWS.Pager            (AWSPager (..))-import           Network.AWS.Prelude          as AWS-import qualified Network.AWS.Presign          as Sign-import           Network.AWS.Request          (requestURL)-import           Network.AWS.Types            hiding (LogLevel (..))-import           Network.AWS.Waiter           (Accept, Wait)--type AWST = AWST' Env--newtype AWST' r m a = AWST' { unAWST :: ReaderT r m a }-    deriving-        ( Functor-        , Applicative-        , Alternative-        , Monad-        , MonadPlus-        , MonadIO-        , MonadActive-        , MonadTrans-        )--instance MonadThrow m => MonadThrow (AWST' r m) where-    throwM = lift . throwM--instance MonadCatch m => MonadCatch (AWST' r m) where-    catch (AWST' m) f = AWST' (catch m (unAWST . f))--instance MonadMask m => MonadMask (AWST' r m) where-    mask a = AWST' $ mask $ \u ->-        unAWST $ a (AWST' . u . unAWST)--    uninterruptibleMask a = AWST' $ uninterruptibleMask $ \u ->-        unAWST $ a (AWST' . u . unAWST)--instance MonadBase b m => MonadBase b (AWST' r m) where-    liftBase = liftBaseDefault--instance MonadTransControl (AWST' r) where-    type StT (AWST' r) a = StT (ReaderT r) a--    liftWith = defaultLiftWith AWST' unAWST-    restoreT = defaultRestoreT AWST'--instance MonadBaseControl b m => MonadBaseControl b (AWST' r m) where-    type StM (AWST' r m) a = ComposeSt (AWST' r) m a--    liftBaseWith = defaultLiftBaseWith-    restoreM     = defaultRestoreM--instance MonadResource m => MonadResource (AWST' r m) where-    liftResourceT = lift . liftResourceT--instance MonadError e m => MonadError e (AWST' r m) where-    throwError     = lift . throwError-    catchError m f = AWST' (unAWST m `catchError` (unAWST . f))--instance Monad m => MonadReader r (AWST' r m) where-    ask     = AWST' ask-    local f = AWST' . local f . unAWST-    reader  = AWST' . reader--instance MonadWriter w m => MonadWriter w (AWST' r m) where-    writer = lift . writer-    tell   = lift . tell-    listen = AWST' . listen . unAWST-    pass   = AWST' . pass   . unAWST--instance MonadState s m => MonadState s (AWST' r m) where-    get = lift get-    put = lift . put--instance MFunctor (AWST' r) where-    hoist nat = AWST' . hoist nat . unAWST---- | Run an 'AWST' action with the specified environment.-runAWST :: HasEnv r => r -> AWST' r m a -> m a-runAWST r (AWST' m) = runReaderT m r---- | An alias for the constraints required to send requests,--- which 'AWST' implicitly fulfils.-type AWSConstraint r m =-    ( MonadCatch     m-    , MonadResource  m-    , MonadReader  r m-    , HasEnv       r-    )---- | Send a request, returning the associated response if successful.------ Throws 'Error'.-send :: (AWSConstraint r m, AWSRequest a)-     => a-     -> m (Rs a)-send = retrier >=> fmap snd . hoistError---- | Repeatedly send a request, automatically setting markers and--- paginating over multiple responses while available.------ Throws 'Error'.-paginate :: (AWSConstraint r m, AWSPager a)-         => a-         -> Source m (Rs a)-paginate = go-  where-    go !x = do-        !y <- send x-        yield y-        maybe (pure ()) go (page x y)---- | Poll the API with the supplied request until a specific 'Wait' condition--- is fulfilled.------ Throws 'Error'.-await :: (AWSConstraint r m, AWSRequest a)-      => Wait a-      -> a-      -> m Accept-await w = waiter w >=> hoistError---- | Presign an URL that is valid from the specified time until the--- number of seconds expiry has elapsed.-presignURL :: ( MonadIO m-              , MonadReader r m-              , HasEnv r-              , AWSRequest a-              )-           => UTCTime     -- ^ Signing time.-           -> Seconds     -- ^ Expiry time.-           -> a           -- ^ Request to presign.-           -> m ByteString-presignURL ts ex = liftM requestURL . presign ts ex---- | Presign an HTTP request that is valid from the specified time until the--- number of seconds expiry has elapsed.-presign :: ( MonadIO m-           , MonadReader r m-           , HasEnv r-           , AWSRequest a-           )-        => UTCTime     -- ^ Signing time.-        -> Seconds     -- ^ Expiry time.-        -> a           -- ^ Request to presign.-        -> m ClientRequest-presign ts ex x = do-    Env{..} <- view environment-    Sign.presignWith (appEndo (getDual _envOverride)) _envAuth _envRegion ts ex x---- | Test whether the underlying host is running on EC2.--- This is memoised and any external check occurs for the first invocation only.-isEC2 :: (MonadIO m, MonadReader r m, HasEnv r) => m Bool-isEC2 = do-    ref <- view envEC2-    mp  <- liftIO (readIORef ref)-    case mp of-        Just p  -> return p-        Nothing -> do-            m  <- view envManager-            !p <- EC2.isEC2 m-            liftIO (atomicWriteIORef ref (Just p))-            return p---- | Retrieve the specified 'Dynamic' data.------ Throws 'HttpException'.-dynamic :: (MonadIO m, MonadThrow m, MonadReader r m, HasEnv r)-        => EC2.Dynamic-        -> m ByteString-dynamic d = view envManager >>= flip EC2.dynamic d---- | Retrieve the specified 'Metadata'.------ Throws 'HttpException'.-metadata :: (MonadIO m, MonadThrow m, MonadReader r m, HasEnv r)-         => EC2.Metadata-         -> m ByteString-metadata m = view envManager >>= flip EC2.metadata m---- | Retrieve the user data. Returns 'Nothing' if no user data is assigned--- to the instance.------ Throws 'HttpException'.-userdata :: (MonadIO m, MonadCatch m, MonadReader r m, HasEnv r)-         => m (Maybe ByteString)-userdata = view envManager >>= EC2.userdata--hoistError :: MonadThrow m => Either Error a -> m a-hoistError = either (throwingM _Error) return--{- $discovery-AuthN/AuthZ information is handled similarly to other AWS SDKs. You can read-some of the options available <http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs here>.--When running on an EC2 instance and using 'FromProfile' or 'Discover', a thread-is forked which transparently handles the expiry and subsequent refresh of IAM-profile information. See 'Network.AWS.Auth.fromProfileName' for more information.--}--{- $sending-To send a request you need to create a value of the desired operation type using-the relevant constructor, as well as any further modifications of default/optional-parameters using the appropriate lenses. This value can then be sent using 'send'-or 'paginate' and the library will take care of serialisation/authentication and-so forth.--The default 'Service' configuration for a request contains retry configuration that is used to-determine if a request can safely be retried and what kind of back off/on strategy-should be used. (Usually exponential.)-Typically services define retry strategies that handle throttling, general server-errors and transport errors. Streaming requests are never retried.--}--{- $pagination-Some AWS operations return results that are incomplete and require subsequent-requests in order to obtain the entire result set. The process of sending-subsequent requests to continue where a previous request left off is called-pagination. For example, the 'ListObjects' operation of Amazon S3 returns up to-1000 objects at a time, and you must send subsequent requests with the-appropriate Marker in order to retrieve the next page of results.--Operations that have an 'AWSPager' instance can transparently perform subsequent-requests, correctly setting Markers and other request facets to iterate through-the entire result set of a truncated API operation. Operations which support-this have an additional note in the documentation.--Many operations have the ability to filter results on the server side. See the-individual operation parameters for details.--}--{- $waiters-Waiters poll by repeatedly sending a request until some remote success condition-configured by the 'Wait' specification is fulfilled. The 'Wait' specification-determines how many attempts should be made, in addition to delay and retry strategies.-Error conditions that are not handled by the 'Wait' configuration will be thrown,-or the first successful response that fulfills the success condition will be-returned.--'Wait' specifications can be found under the @Network.AWS.{ServiceName}.Waiters@-namespace for services which support 'await'.--}--{- $service-When a request is sent, various values such as the endpoint,-retry strategy, timeout and error handlers are taken from the associated 'Service'-for a request. For example, 'DynamoDB' will use the 'Network.AWS.DynamoDB.dynamoDB'-configuration when sending 'PutItem', 'Query' and all other operations.--You can modify a specific 'Service''s default configuration by using-'configure' or 'reconfigure'. To modify all configurations simultaneously, see 'override'.--An example of how you might alter default configuration using these mechanisms-is demonstrated below. Firstly, the default 'dynamoDB' service is configured to-use non-SSL localhost as the endpoint:--> let dynamo :: Service->     dynamo = setEndpoint False "localhost" 8000 dynamoDB--The updated configuration is then passed to the 'Env' during setup:--> e <- newEnv Discover <&> configure dynamo-> runResourceT . runAWS e $ do->     -- This S3 operation will communicate with remote AWS APIs.->     x <- send listBuckets->->     -- DynamoDB operations will communicate with localhost:8000.->     y <- send listTables->->     -- Any operations for services other than DynamoDB, are not affected.->     ...--You can also scope the 'Endpoint' modifications (or any other 'Service' configuration)-to specific actions:--> e <- newEnv Discover-> runResourceT . runAWS e $ do->     -- Service operations here will communicate with AWS, even DynamoDB.->     x <- send listTables->->     reconfigure dynamo $ do->        -- In here, DynamoDB operations will communicate with localhost:8000,->        -- with operations for services not being affected.->        ...--Functions such as 'within', 'once', and 'timeout' likewise modify the underlying-configuration for all service requests within their respective scope.--}--{- $streaming-Streaming comes in two flavours. 'HashedBody' represents a request-that requires a precomputed 'SHA256' hash, or a 'ChunkedBody' type for those services-that can perform incremental signing and do not require the entire payload to-be hashed (such as 'S3'). The type signatures for request smart constructors-advertise which respective body type is required, denoting the underlying signing-capabilities.--'ToHashedBody' and 'ToBody' typeclass instances are available to construct the-streaming bodies, automatically calculating any hash or size as needed for types-such as 'Text', 'ByteString', or Aeson's 'Value' type. To read files and other-'IO' primitives, functions such as 'hashedFile', 'chunkedFile', or 'hashedBody'-should be used.--For responses that contain streaming bodies (such as 'GetObject'), you can use-'sinkBody' to connect the response body to a <http://hackage.haskell.org/package/conduit conduit>-compatible sink.--}--{- $presigning-Presigning requires the 'Service' signer to be an instance of 'AWSPresigner'.-Not all signing algorithms support this.--}--{- $metadata-Metadata can be retrieved from the underlying host assuming that you're running-the code on an EC2 instance or have a compatible @instance-data@ endpoint available.--}--{- $async-Requests can be sent asynchronously, but due to guarantees about resource closure-require the use of <http://hackage.haskell.org/package/lifted-async lifted-async>.--The following example demonstrates retrieving two objects from S3 concurrently:--> import Control.Concurrent.Async.Lifted-> import Control.Lens-> import Control.Monad.Trans.AWS-> import Network.AWS.S3->-> do x   <- async . send $ getObject "bucket" "prefix/object-foo"->    y   <- async . send $ getObject "bucket" "prefix/object-bar"->    foo <- wait x->    bar <- wait y->    ...--/See:/ <http://hackage.haskell.org/package/lifted-async Control.Concurrent.Async.Lifted>--}--{- $errors-Errors are thrown by the library using 'MonadThrow' (unless "Control.Monad.Error.AWS" is used).-Sub-errors of the canonical 'Error' type can be caught using 'trying' or-'catching' and the appropriate 'AsError' 'Prism':--@-trying '_Error'          (send $ ListObjects "bucket-name") :: Either 'Error'          ListObjectsResponse-trying '_TransportError' (send $ ListObjects "bucket-name") :: Either 'HttpException'  ListObjectsResponse-trying '_SerializeError' (send $ ListObjects "bucket-name") :: Either 'SerializeError' ListObjectsResponse-trying '_ServiceError'   (send $ ListObjects "bucket-name") :: Either 'ServiceError'   ListObjectsResponse-@--Many of the individual @amazonka-*@ libraries export compatible 'Getter's for-matching service specific error codes and messages in the style above.-See the @Error Matchers@ heading in each respective library for details.--}--{- $logging-The exposed logging interface is a primitive 'Logger' function which gets-threaded through service calls and serialisation routines. This allows the-library to output useful information and diagnostics.--The 'newLogger' function can be used to construct a simple logger which writes-output to a 'Handle', but in most production code you should probably consider-using a more robust logging library such as-<http://hackage.haskell.org/package/tiny-log tiny-log> or-<http://hackage.haskell.org/package/fast-logger fast-logger>.--}
− src/Network/AWS.hs
@@ -1,520 +0,0 @@-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE RankNTypes        #-}--{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}---- |--- Module      : Network.AWS--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : provisional--- Portability : non-portable (GHC extensions)------ This module provides a simple 'AWS' monad and a set of operations which--- can be performed against remote Amazon Web Services APIs, for use with the types--- supplied by the various @amazonka-*@ libraries.------ A 'MonadAWS' typeclass is used as a function constraint to provide automatic--- lifting of functions when embedding 'AWS' as a layer inside your own--- application stack.------ "Control.Monad.Trans.AWS" contains the underlying 'AWST' transformer.-module Network.AWS-    (-    -- * Usage-    -- $usage--    -- * Running AWS Actions-      AWS-    , MonadAWS    (..)-    , runAWS-    , runResourceT--    -- * Authentication and Environment-    , newEnv-    , Env-    , HasEnv       (..)--    -- ** Credential Discovery-    , Credentials  (..)-    -- $discovery--    -- ** Supported Regions-    , Region       (..)--    -- * Sending Requests-    -- $sending--    , send--    -- ** Pagination-    -- $pagination--    , paginate--    -- ** Waiters-    -- $waiters--    , await--    -- ** Service Configuration-    -- $service--    -- *** Overriding Defaults-    , Env.configure-    , Env.override--    -- *** Scoped Actions-    , reconfigure-    , within-    , once-    , timeout--    -- ** Streaming-    -- $streaming--    -- *** Request Bodies-    , ToHashedBody (..)-    , hashedFile-    , hashedBody--    -- *** Chunked Request Bodies-    , ToBody       (..)-    , ChunkSize    (..)-    , defaultChunkSize-    , chunkedFile-    , unsafeChunkedBody--    -- *** Response Bodies-    , sinkBody--    -- *** File Size and MD5/SHA256-    , getFileSize-    , sinkMD5-    , sinkSHA256--    -- * Presigning Requests-    -- $presigning--    , presignURL--    -- * EC2 Instance Metadata-    -- $metadata--    , isEC2-    , dynamic-    , metadata-    , userdata--    , EC2.Dynamic  (..)-    , EC2.Metadata (..)--    -- * Running Asynchronous Actions-    -- $async--    -- * Handling Errors-    -- $errors--    , AsError      (..)-    , AsAuthError  (..)--    , AWST.trying-    , AWST.catching--    -- * Logging-    -- $logging--    , Logger-    , LogLevel     (..)--    -- ** Constructing a Logger-    , newLogger--    -- ** Endpoints-    , Endpoint-    , AWST.setEndpoint--    -- * Re-exported Types-    , module Network.AWS.Types-    , module Network.AWS.Waiter-    , module Network.AWS.Pager-    , RqBody-    , HashedBody-    , ChunkedBody-    , RsBody-    ) where--import           Control.Applicative-import           Control.Monad.Catch          (MonadCatch)-import           Control.Monad.IO.Class       (MonadIO)-import           Control.Monad.Morph          (hoist)-import qualified Control.Monad.RWS.Lazy       as LRW-import qualified Control.Monad.RWS.Strict     as RW-import qualified Control.Monad.State.Lazy     as LS-import qualified Control.Monad.State.Strict   as S-import           Control.Monad.Trans.AWS      (AWST)-import qualified Control.Monad.Trans.AWS      as AWST-import           Control.Monad.Trans.Class    (lift)-import           Control.Monad.Trans.Except   (ExceptT)-import           Control.Monad.Trans.Identity (IdentityT)-import           Control.Monad.Trans.List     (ListT)-import           Control.Monad.Trans.Maybe    (MaybeT)-import           Control.Monad.Trans.Reader   (ReaderT)-import           Control.Monad.Trans.Resource-import qualified Control.Monad.Writer.Lazy    as LW-import qualified Control.Monad.Writer.Strict  as W-import           Data.Conduit                 (Source)-import           Data.Monoid-import           Network.AWS.Auth-import qualified Network.AWS.EC2.Metadata     as EC2-import           Network.AWS.Env              (Env, HasEnv (..), newEnv)-import qualified Network.AWS.Env              as Env-import           Network.AWS.Internal.Body-import           Network.AWS.Internal.Logger-import           Network.AWS.Lens             ((^.))-import           Network.AWS.Pager            (AWSPager)-import           Network.AWS.Prelude-import           Network.AWS.Types            hiding (LogLevel (..))-import           Network.AWS.Waiter           (Wait)---- | A specialisation of the 'AWST' transformer.-type AWS = AWST (ResourceT IO)---- | Monads in which 'AWS' actions may be embedded.-class ( Functor     m-      , Applicative m-      , Monad       m-      , MonadIO     m-      , MonadCatch  m-      ) => MonadAWS m where-    -- | Lift a computation to the 'AWS' monad.-    liftAWS :: AWS a -> m a--instance MonadAWS AWS where-    liftAWS = id--instance MonadAWS m => MonadAWS (IdentityT   m) where liftAWS = lift . liftAWS-instance MonadAWS m => MonadAWS (ListT       m) where liftAWS = lift . liftAWS-instance MonadAWS m => MonadAWS (MaybeT      m) where liftAWS = lift . liftAWS-instance MonadAWS m => MonadAWS (ExceptT   e m) where liftAWS = lift . liftAWS-instance MonadAWS m => MonadAWS (ReaderT   r m) where liftAWS = lift . liftAWS-instance MonadAWS m => MonadAWS (S.StateT  s m) where liftAWS = lift . liftAWS-instance MonadAWS m => MonadAWS (LS.StateT s m) where liftAWS = lift . liftAWS--instance (Monoid w, MonadAWS m) => MonadAWS (W.WriterT w m) where-    liftAWS = lift . liftAWS--instance (Monoid w, MonadAWS m) => MonadAWS (LW.WriterT w m) where-    liftAWS = lift . liftAWS--instance (Monoid w, MonadAWS m) => MonadAWS (RW.RWST r w s m) where-    liftAWS = lift . liftAWS--instance (Monoid w, MonadAWS m) => MonadAWS (LRW.RWST r w s m) where-    liftAWS = lift . liftAWS---- | Run the 'AWS' monad. Any outstanding HTTP responses' 'ResumableSource' will--- be closed when the 'ResourceT' computation is unwrapped with 'runResourceT'.------ Throws 'Error', which will include 'HTTPExceptions', serialisation errors,--- or any particular errors returned by the respective AWS service.------ /See:/ 'AWST.runAWST', 'runResourceT'.-runAWS :: (MonadResource m, HasEnv r) => r -> AWS a -> m a-runAWS e = liftResourceT . AWST.runAWST (e ^. environment)---- | Scope an action such that all requests belonging to the supplied service--- will use this configuration instead of the default.------ It's suggested you use a modified version of the default service, such--- as @Network.AWS.DynamoDB.dynamoDB@.------ /See:/ 'Env.configure'.-reconfigure :: MonadAWS m => Service -> AWS a -> m a-reconfigure s = liftAWS . AWST.reconfigure s---- | Scope an action within the specific 'Region'.-within :: MonadAWS m => Region -> AWS a -> m a-within r = liftAWS . AWST.within r---- | Scope an action such that any retry logic for the 'Service' is--- ignored and any requests will at most be sent once.-once :: MonadAWS m => AWS a -> m a-once = liftAWS . AWST.once---- | Scope an action such that any HTTP response will use this timeout value.-timeout :: MonadAWS m => Seconds -> AWS a -> m a-timeout s = liftAWS . AWST.timeout s---- | Send a request, returning the associated response if successful.-send :: (MonadAWS m, AWSRequest a) => a -> m (Rs a)-send = liftAWS . AWST.send---- | Repeatedly send a request, automatically setting markers and--- paginating over multiple responses while available.-paginate :: (MonadAWS m, AWSPager a) => a -> Source m (Rs a)-paginate = hoist liftAWS . AWST.paginate---- | Poll the API with the supplied request until a specific 'Wait' condition--- is fulfilled.-await :: (MonadAWS m, AWSRequest a) => Wait a -> a -> m AWST.Accept-await w = liftAWS . AWST.await w---- | Presign an URL that is valid from the specified time until the--- number of seconds expiry has elapsed.-presignURL :: (MonadAWS m, AWSRequest a)-           => UTCTime     -- ^ Signing time.-           -> Seconds     -- ^ Expiry time.-           -> a           -- ^ Request to presign.-           -> m ByteString-presignURL t ex = liftAWS . AWST.presignURL t ex---- | Test whether the underlying host is running on EC2.--- This is memoised and an HTTP request is made to the host's metadata--- endpoint for the first call only.-isEC2 :: MonadAWS m => m Bool-isEC2 = liftAWS AWST.isEC2---- | Retrieve the specified 'Dynamic' data.-dynamic :: MonadAWS m => EC2.Dynamic -> m ByteString-dynamic = liftAWS . AWST.dynamic---- | Retrieve the specified 'Metadata'.-metadata :: MonadAWS m => EC2.Metadata -> m ByteString-metadata = liftAWS . AWST.metadata---- | Retrieve the user data. Returns 'Nothing' if no user data is assigned--- to the instance.-userdata :: MonadAWS m => m (Maybe ByteString)-userdata = liftAWS AWST.userdata--{- $usage-The key functions dealing with the request/response lifecycle are:--* 'send'--* 'paginate'--* 'await'--These functions have constraints that types from the @amazonka-*@ libraries-satisfy. To utilise these, you will need to specify what 'Region' you wish to-operate in and your Amazon credentials for AuthN/AuthZ purposes.--'Credentials' can be supplied in a number of ways. Either via explicit keys,-via session profiles, or have Amazonka retrieve the credentials from an-underlying IAM Role/Profile.--As a basic example, you might wish to store an object in an S3 bucket using-<http://hackage.haskell.org/package/amazonka-s3 amazonka-s3>:--@-{-# LANGUAGE OverloadedStrings #-}--import Control.Lens-import Network.AWS-import Network.AWS.S3-import System.IO--example :: IO PutObjectResponse-example = do-    -- A new 'Logger' to replace the default noop logger is created, with the logger-    -- set to print debug information and errors to stdout:-    lgr  <- newLogger Debug stdout--    -- To specify configuration preferences, 'newEnv' is used to create a new-    -- configuration environment. The 'Credentials' parameter is used to specify-    -- mechanism for supplying or retrieving AuthN/AuthZ information.-    -- In this case 'Discover' will cause the library to try a number of options such-    -- as default environment variables, or an instance's IAM Profile and identity document:-    env  <- newEnv Discover--    -- The payload (and hash) for the S3 object is retrieved from a 'FilePath':-    body <- sourceFileIO "local\/path\/to\/object-payload"--    -- We now run the 'AWS' computation with the overriden logger, performing the-    -- 'PutObject' request. 'envRegion' or 'within' can be used to set the-    -- remote AWS 'Region':-    runResourceT $ runAWS (env & envLogger .~ lgr) $-        within Frankfurt $-            send (putObject "bucket-name" "object-key" body)-@--}--{- $discovery-AuthN/AuthZ information is handled similarly to other AWS SDKs. You can read-some of the options available <http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs here>.--When running on an EC2 instance and using 'FromProfile' or 'Discover', a thread-is forked which transparently handles the expiry and subsequent refresh of IAM-profile information. See 'Network.AWS.Auth.fromProfileName' for more information.--}--{- $sending-To send a request you need to create a value of the desired operation type using-the relevant constructor, as well as any further modifications of default/optional-parameters using the appropriate lenses. This value can then be sent using 'send'-or 'paginate' and the library will take care of serialisation/authentication and-so forth.--The default 'Service' configuration for a request contains retry configuration that is used to-determine if a request can safely be retried and what kind of back off/on strategy-should be used. (Usually exponential.)-Typically services define retry strategies that handle throttling, general server-errors and transport errors. Streaming requests are never retried.--}--{- $pagination-Some AWS operations return results that are incomplete and require subsequent-requests in order to obtain the entire result set. The process of sending-subsequent requests to continue where a previous request left off is called-pagination. For example, the 'ListObjects' operation of Amazon S3 returns up to-1000 objects at a time, and you must send subsequent requests with the-appropriate Marker in order to retrieve the next page of results.--Operations that have an 'AWSPager' instance can transparently perform subsequent-requests, correctly setting Markers and other request facets to iterate through-the entire result set of a truncated API operation. Operations which support-this have an additional note in the documentation.--Many operations have the ability to filter results on the server side. See the-individual operation parameters for details.--}--{- $waiters-Waiters poll by repeatedly sending a request until some remote success condition-configured by the 'Wait' specification is fulfilled. The 'Wait' specification-determines how many attempts should be made, in addition to delay and retry strategies.-Error conditions that are not handled by the 'Wait' configuration will be thrown,-or the first successful response that fulfills the success condition will be-returned.--'Wait' specifications can be found under the @Network.AWS.{ServiceName}.Waiters@-namespace for services which support 'await'.--}--{- $service-When a request is sent, various values such as the endpoint,-retry strategy, timeout and error handlers are taken from the associated 'Service'-for a request. For example, 'DynamoDB' will use the 'Network.AWS.DynamoDB.dynamoDB'-configuration when sending 'PutItem', 'Query' and all other operations.--You can modify a specific 'Service''s default configuration by using-'configure' or 'reconfigure'. To modify all configurations simultaneously, see 'override'.--An example of how you might alter default configuration using these mechanisms-is demonstrated below. Firstly, the default 'dynamoDB' service is configured to-use non-SSL localhost as the endpoint:--> let dynamo :: Service->     dynamo = setEndpoint False "localhost" 8000 dynamoDB--The updated configuration is then passed to the 'Env' during setup:--> e <- newEnv Frankfurt Discover <&> configure dynamo-> runAWS e $ do->     -- This S3 operation will communicate with remote AWS APIs.->     x <- send listBuckets->->     -- DynamoDB operations will communicate with localhost:8000.->     y <- send listTables->->     -- Any operations for services other than DynamoDB, are not affected.->     ...--You can also scope the 'Endpoint' modifications (or any other 'Service' configuration)-to specific actions:--> e <- newEnv Ireland Discover-> runAWS e $ do->     -- Service operations here will communicate with AWS, even DynamoDB.->     x <- send listTables->->     reconfigure dynamo $ do->        -- In here, DynamoDB operations will communicate with localhost:8000,->        -- with operations for services not being affected.->        ...--Functions such as 'within', 'once', and 'timeout' likewise modify the underlying-configuration for all service requests within their respective scope.--}--{- $streaming-Streaming comes in two flavours. 'HashedBody' represents a request-that requires a precomputed 'SHA256' hash, or a 'ChunkedBody' type for those services-that can perform incremental signing and do not require the entire payload to-be hashed (such as 'S3'). The type signatures for request smart constructors-advertise which respective body type is required, denoting the underlying signing-capabilities.--'ToHashedBody' and 'ToBody' typeclass instances are available to construct the-streaming bodies, automatically calculating any hash or size as needed for types-such as 'Text', 'ByteString', or Aeson's 'Value' type. To read files and other-'IO' primitives, functions such as 'hashedFile', 'chunkedFile', or 'hashedBody'-should be used.--For responses that contain streaming bodies (such as 'GetObject'), you can use-'sinkBody' to connect the response body to a <http://hackage.haskell.org/package/conduit conduit>-compatible sink.--}--{- $presigning-Presigning requires the 'Service' signer to be an instance of 'AWSPresigner'.-Not all signing algorithms support this.--}--{- $metadata-Metadata can be retrieved from the underlying host assuming that you're running-the code on an EC2 instance or have a compatible @instance-data@ endpoint available.--}--{- $async-Requests can be sent asynchronously, but due to guarantees about resource closure-require the use of <http://hackage.haskell.org/package/lifted-async lifted-async>.--The following example demonstrates retrieving two objects from S3 concurrently:--> import Control.Concurrent.Async.Lifted-> import Control.Lens-> import Control.Monad.Trans.AWS-> import Network.AWS.S3->-> do x   <- async . send $ getObject "bucket" "prefix/object-foo"->    y   <- async . send $ getObject "bucket" "prefix/object-bar"->    foo <- wait x->    bar <- wait y->    ...--/See:/ <http://hackage.haskell.org/package/lifted-async Control.Concurrent.Async.Lifted>--}--{- $errors-Errors are thrown by the library using 'MonadThrow' (unless "Control.Monad.Error.AWS" is used).-Sub-errors of the canonical 'Error' type can be caught using 'trying' or-'catching' and the appropriate 'AsError' 'Prism':--@-trying '_Error'          (send $ ListObjects "bucket-name") :: Either 'Error'          ListObjectsResponse-trying '_TransportError' (send $ ListObjects "bucket-name") :: Either 'HttpException'  ListObjectsResponse-trying '_SerializeError' (send $ ListObjects "bucket-name") :: Either 'SerializeError' ListObjectsResponse-trying '_ServiceError'   (send $ ListObjects "bucket-name") :: Either 'ServiceError'   ListObjectsResponse-@--Many of the individual @amazonka-*@ libraries export compatible 'Getter's for-matching service specific error codes and messages in the style above.-See the @Error Matchers@ heading in each respective library for details.--}--{- $logging-The exposed logging interface is a primitive 'Logger' function which gets-threaded through service calls and serialisation routines. This allows the-library to output useful information and diagnostics.--The 'newLogger' function can be used to construct a simple logger which writes-output to a 'Handle', but in most production code you should probably consider-using a more robust logging library such as-<http://hackage.haskell.org/package/tiny-log tiny-log> or-<http://hackage.haskell.org/package/fast-logger fast-logger>.--}
− src/Network/AWS/Auth.hs
@@ -1,524 +0,0 @@-{-# LANGUAGE BangPatterns       #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts   #-}-{-# LANGUAGE LambdaCase         #-}-{-# LANGUAGE OverloadedStrings  #-}---- |--- Module      : Network.AWS.Auth--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : provisional--- Portability : non-portable (GHC extensions)------ Explicitly specify your Amazon AWS security credentials, or retrieve them--- from the underlying OS.------ The format of environment variables and the credentials file follows the official--- <http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs AWS SDK guidelines>.-module Network.AWS.Auth-    (-    -- * Authentication-    -- ** Retrieving Authentication-      getAuth-    , Credentials  (..)-    , Auth--    -- ** Defaults-    -- *** Environment-    , envAccessKey-    , envSecretKey-    , envSessionToken--    -- *** Credentials File-    , credAccessKey-    , credSecretKey-    , credSessionToken-    , credProfile-    , credFile--    -- ** Credentials-    -- $credentials--    , fromKeys-    , fromSession-    , fromEnv-    , fromEnvKeys-    , fromFile-    , fromFilePath-    , fromProfile-    , fromProfileName--    -- ** Keys-    , AccessKey    (..)-    , SecretKey    (..)-    , SessionToken (..)--    -- ** Handling Errors-    , AsAuthError  (..)-    , AuthError    (..)-    ) where--import           Control.Applicative-import           Control.Concurrent-import           Control.Monad-import           Control.Monad.Catch-import           Control.Monad.IO.Class-import           Control.Monad.Trans.Maybe  (MaybeT (..))-import qualified Data.ByteString.Char8      as BS8-import qualified Data.ByteString.Lazy.Char8 as LBS8-import           Data.Char                  (isSpace)-import qualified Data.Ini                   as INI-import           Data.IORef-import           Data.Monoid-import qualified Data.Text                  as Text-import qualified Data.Text.Encoding         as Text-import           Data.Time                  (diffUTCTime, getCurrentTime)-import           Network.AWS.Data.Log-import           Network.AWS.EC2.Metadata-import           Network.AWS.Lens           (catching, catching_, exception,-                                             throwingM, _IOException)-import           Network.AWS.Lens           (Prism', prism, (<&>))-import           Network.AWS.Prelude-import           Network.AWS.Types-import           Network.HTTP.Conduit-import           System.Directory           (doesFileExist, getHomeDirectory)-import           System.Environment-import           System.Mem.Weak---- | Default access key environment variable.-envAccessKey :: Text -- ^ AWS_ACCESS_KEY_ID-envAccessKey = "AWS_ACCESS_KEY_ID"---- | Default secret key environment variable.-envSecretKey :: Text -- ^ AWS_SECRET_ACCESS_KEY-envSecretKey = "AWS_SECRET_ACCESS_KEY"---- | Default session token environment variable.-envSessionToken :: Text -- ^ AWS_SESSION_TOKEN-envSessionToken = "AWS_SESSION_TOKEN"---- | Default credentials profile environment variable.-envProfile :: Text -- ^ AWS_PROFILE-envProfile = "AWS_PROFILE"---- | Default region environment variable-envRegion :: Text -- ^ AWS_REGION-envRegion = "AWS_REGION"---- | Credentials INI file access key variable.-credAccessKey :: Text -- ^ aws_access_key_id-credAccessKey = "aws_access_key_id"---- | Credentials INI file secret key variable.-credSecretKey :: Text -- ^ aws_secret_access_key-credSecretKey = "aws_secret_access_key"---- | Credentials INI file session token variable.-credSessionToken :: Text -- ^ aws_session_token-credSessionToken = "aws_session_token"---- | Credentials INI default profile section variable.-credProfile :: Text -- ^ default-credProfile = "default"---- | Default path for the credentials file. This looks in in the @HOME@ directory--- as determined by the <http://hackage.haskell.org/package/directory directory>--- library.------ * UNIX/OSX: @$HOME/.aws/credentials@------ * Windows: @C:\/Users\//\<user\>\.aws\credentials@------ /Note:/ This does not match the default AWS SDK location of--- @%USERPROFILE%\.aws\credentials@ on Windows. (Sorry.)-credFile :: (MonadCatch m, MonadIO m) => m FilePath-credFile = catching_ _IOException dir err-  where-    dir = (++ p) `liftM` liftIO getHomeDirectory-    err = throwM $ MissingFileError ("$HOME" ++ p)--    -- TODO: probably should be using System.FilePath above.-    p = "/.aws/credentials"--{- $credentials-'getAuth' is implemented using the following @from*@-styled functions below.-Both 'fromKeys' and 'fromSession' can be used directly to avoid the 'MonadIO'-constraint.--}---- | Explicit access and secret keys.-fromKeys :: AccessKey -> SecretKey -> Auth-fromKeys a s = Auth (AuthEnv a s Nothing Nothing)---- | A session containing the access key, secret key, and a session token.-fromSession :: AccessKey -> SecretKey -> SessionToken -> Auth-fromSession a s t = Auth (AuthEnv a s (Just t) Nothing)---- | Determines how AuthN/AuthZ information is retrieved.-data Credentials-    = FromKeys AccessKey SecretKey-      -- ^ Explicit access and secret keys. See 'fromKeys'.--    | FromSession AccessKey SecretKey SessionToken-      -- ^ Explicit access key, secret key and a session token. See 'fromSession'.--    | FromEnv Text Text (Maybe Text) (Maybe Text)-      -- ^ Lookup specific environment variables for access key, secret key,-      -- an optional session token, and an optional region, respectively.--    | FromProfile Text-      -- ^ An IAM Profile name to lookup from the local EC2 instance-data.-      -- Environment variables to lookup for the access key, secret key and-      -- optional session token.--    | FromFile Text FilePath-      -- ^ A credentials profile name (the INI section) and the path to the AWS-      -- <http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs credentials> file.--    | Discover-      -- ^ Attempt credentials discovery via the following steps:-      ---      -- * Read the 'envAccessKey', 'envSecretKey', and 'envRegion' from the environment if they are set.-      ---      -- * Read the credentials file if 'credFile' exists.-      ---      -- * Retrieve the first available IAM profile and read-      -- the 'Region' from the instance identity document, if running on EC2.-      ---      -- An attempt is made to resolve <http://instance-data> rather than directly-      -- retrieving <http://169.254.169.254> for IAM profile information.-      -- This assists in ensuring the DNS lookup terminates promptly if not-      -- running on EC2.-      deriving (Eq)--instance ToLog Credentials where-    build = \case-        FromKeys    a _ ->-            "FromKeys " <> build a <> " ****"-        FromSession a _ _ ->-            "FromSession " <> build a <> " **** ****"-        FromEnv     a s t r ->-            "FromEnv " <> build a <> " " <> build s <> " " <> m t <> " " <> m r-        FromProfile n ->-            "FromProfile " <> build n-        FromFile    n f ->-            "FromFile " <> build n <> " " <> build f-        Discover ->-            "Discover"-      where-        m (Just x) = "(Just " <> build x <> ")"-        m Nothing  = "Nothing"--instance Show Credentials where-    show = BS8.unpack . toBS . build---- | An error thrown when attempting to read AuthN/AuthZ information.-data AuthError-    = RetrievalError   HttpException-    | MissingEnvError  Text-    | InvalidEnvError  Text-    | MissingFileError FilePath-    | InvalidFileError Text-    | InvalidIAMError  Text-      deriving (Show, Typeable)--instance Exception AuthError--instance ToLog AuthError where-    build = \case-        RetrievalError   e -> build e-        MissingEnvError  e -> "[MissingEnvError]  { message = " <> build e <> "}"-        InvalidEnvError  e -> "[InvalidEnvError]  { message = " <> build e <> "}"-        MissingFileError f -> "[MissingFileError] { path = "    <> build f <> "}"-        InvalidFileError e -> "[InvalidFileError] { message = " <> build e <> "}"-        InvalidIAMError  e -> "[InvalidIAMError]  { message = " <> build e <> "}"--class AsAuthError a where-    -- | A general authentication error.-    _AuthError        :: Prism' a AuthError-    {-# MINIMAL _AuthError #-}--    -- | An error occured while communicating over HTTP with-    -- the local metadata endpoint.-    _RetrievalError   :: Prism' a HttpException--    -- | The named environment variable was not found.-    _MissingEnvError  :: Prism' a Text--    -- | An error occured parsing named environment variable's value.-    _InvalidEnvError  :: Prism' a Text--    -- | The specified credentials file could not be found.-    _MissingFileError :: Prism' a FilePath--    -- | An error occured parsing the credentials file.-    _InvalidFileError :: Prism' a Text--    -- | The specified IAM profile could not be found or deserialised.-    _InvalidIAMError  :: Prism' a Text--    _RetrievalError   = _AuthError . _RetrievalError-    _MissingEnvError  = _AuthError . _MissingEnvError-    _InvalidEnvError  = _AuthError . _InvalidEnvError-    _MissingFileError = _AuthError . _MissingFileError-    _InvalidFileError = _AuthError . _InvalidFileError-    _InvalidIAMError  = _AuthError . _InvalidIAMError--instance AsAuthError SomeException where-    _AuthError = exception--instance AsAuthError AuthError where-    _AuthError = id--    _RetrievalError = prism RetrievalError $ \case-        RetrievalError   e -> Right e-        x                  -> Left  x--    _MissingEnvError = prism MissingEnvError $ \case-        MissingEnvError  e -> Right e-        x                  -> Left  x--    _InvalidEnvError = prism InvalidEnvError $ \case-        InvalidEnvError  e -> Right e-        x                  -> Left  x--    _MissingFileError = prism MissingFileError $ \case-        MissingFileError f -> Right f-        x                  -> Left  x--    _InvalidFileError = prism InvalidFileError $ \case-        InvalidFileError e -> Right e-        x                  -> Left  x--    _InvalidIAMError = prism InvalidIAMError $ \case-        InvalidIAMError  e -> Right e-        x                  -> Left  x---- | Retrieve authentication information via the specified 'Credentials' mechanism.------ Throws 'AuthError' when environment variables or IAM profiles cannot be read,--- and credentials files are invalid or cannot be found.-getAuth :: (Applicative m, MonadIO m, MonadCatch m)-        => Manager-        -> Credentials-        -> m (Auth, Maybe Region)-getAuth m = \case-    FromKeys    a s     -> return (fromKeys a s, Nothing)-    FromSession a s t   -> return (fromSession a s t, Nothing)-    FromEnv     a s t r -> fromEnvKeys a s t r-    FromProfile n       -> fromProfileName m n-    FromFile    n f     -> fromFilePath n f-    Discover            ->-        -- Don't try and catch InvalidFileError, or InvalidIAMProfile,-        -- let both errors propagate.-        catching_ _MissingEnvError fromEnv $-            -- proceed, missing env keys-            catching _MissingFileError fromFile $ \f -> do-                -- proceed, missing credentials file-                p <- isEC2 m-                unless p $-                    -- not an EC2 instance, rethrow the previous error.-                    throwingM _MissingFileError f-                 -- proceed, check EC2 metadata for IAM information.-                fromProfile m---- | Retrieve access key, secret key, and a session token from the default--- environment variables.------ Throws 'MissingEnvError' if either of the default environment variables--- cannot be read, but not if the session token is absent.------ /See:/ 'envAccessKey', 'envSecretKey', 'envSessionToken'-fromEnv :: (Applicative m, MonadIO m, MonadThrow m) => m (Auth, Maybe Region)-fromEnv =-    fromEnvKeys-        envAccessKey-        envSecretKey-        (Just envSessionToken)-        (Just envRegion)---- | Retrieve access key, secret key and a session token from specific--- environment variables.------ Throws 'MissingEnvError' if either of the specified key environment variables--- cannot be read, but not if the session token is absent.-fromEnvKeys :: (Applicative m, MonadIO m, MonadThrow m)-            => Text       -- ^ Access key environment variable.-            -> Text       -- ^ Secret key environment variable.-            -> Maybe Text -- ^ Session token environment variable.-            -> Maybe Text -- ^ Region environment variable.-            -> m (Auth, Maybe Region)-fromEnvKeys access secret session region =-    (,) <$> fmap Auth lookupKeys <*> lookupRegion-  where-    lookupKeys = AuthEnv-        <$> (req access  <&> AccessKey . BS8.pack)-        <*> (req secret  <&> SecretKey . BS8.pack)-        <*> (opt session <&> fmap (SessionToken . BS8.pack))-        <*> return Nothing--    lookupRegion :: (MonadIO m, MonadThrow m) => m (Maybe Region)-    lookupRegion = runMaybeT $ do-        k <- MaybeT (return region)-        r <- MaybeT (opt region)-        case fromText (Text.pack r) of-            Right x -> return x-            Left  e -> throwM . InvalidEnvError $-                "Unable to parse ENV variable: " <> k <> ", " <> Text.pack e--    req k = do-        m <- opt (Just k)-        maybe (throwM . MissingEnvError $ "Unable to read ENV variable: " <> k)-              return-              m--    opt Nothing  = return Nothing-    opt (Just k) = liftIO (lookupEnv (Text.unpack k))---- | Loads the default @credentials@ INI file using the default profile name.------ Throws 'MissingFileError' if 'credFile' is missing, or 'InvalidFileError'--- if an error occurs during parsing.------ /See:/ 'credProfile', 'credFile', and 'envProfile'-fromFile :: (Applicative m, MonadIO m, MonadCatch m) => m (Auth, Maybe Region)-fromFile = do-  p <- liftIO (lookupEnv (Text.unpack envProfile))-  fromFilePath (maybe credProfile Text.pack p)-      =<< credFile---- | Retrieve the access, secret and session token from the specified section--- (profile) in a valid INI @credentials@ file.------ Throws 'MissingFileError' if the specified file is missing, or 'InvalidFileError'--- if an error occurs during parsing.-fromFilePath :: (Applicative m, MonadIO m, MonadCatch m)-             => Text-             -> FilePath-             -> m (Auth, Maybe Region)-fromFilePath n f = do-    p <- liftIO (doesFileExist f)-    unless p $-        throwM (MissingFileError f)-    ini <- either (invalidErr Nothing) return =<< liftIO (INI.readIniFile f)-    env <- AuthEnv-        <$> (req credAccessKey    ini <&> AccessKey)-        <*> (req credSecretKey    ini <&> SecretKey)-        <*> (opt credSessionToken ini <&> fmap SessionToken)-        <*> return Nothing-    return (Auth env, Nothing)-  where-    req k i =-        case INI.lookupValue n k i of-            Left  e         -> invalidErr (Just k) e-            Right x-                | blank x   -> invalidErr (Just k) "cannot be a blank string."-                | otherwise -> return (Text.encodeUtf8 x)--    opt k i = return $-        case INI.lookupValue n k i of-            Left  _ -> Nothing-            Right x -> Just (Text.encodeUtf8 x)--    invalidErr Nothing  e = throwM $ InvalidFileError (Text.pack e)-    invalidErr (Just k) e = throwM $ InvalidFileError-        (Text.pack f <> ", key " <> k <> " " <> Text.pack e)--    blank x = Text.null x || Text.all isSpace x---- | Retrieve the default IAM Profile from the local EC2 instance-data.------ The default IAM profile is determined by Amazon as the first profile found--- in the response from:--- @http://169.254.169.254/latest/meta-data/iam/security-credentials/@------ Throws 'RetrievalError' if the HTTP call fails, or 'InvalidIAMError' if--- the default IAM profile cannot be read.-fromProfile :: (MonadIO m, MonadCatch m) => Manager -> m (Auth, Maybe Region)-fromProfile m = do-    ls <- try $ metadata m (IAM (SecurityCredentials Nothing))-    case BS8.lines `liftM` ls of-        Right (x:_) -> fromProfileName m (Text.decodeUtf8 x)-        Left  e     -> throwM (RetrievalError e)-        _           -> throwM $-            InvalidIAMError "Unable to get default IAM Profile from EC2 metadata"---- | Lookup a specific IAM Profile by name from the local EC2 instance-data.------ The resulting IONewRef wrapper + timer is designed so that multiple concurrent--- accesses of 'AuthEnv' from the 'AWS' environment are not required to calculate--- expiry and sequentially queue to update it.------ The forked timer ensures a singular owner and pre-emptive refresh of the--- temporary session credentials.------ A weak reference is used to ensure that the forked thread will eventually--- terminate when 'Auth' is no longer referenced.------ Throws 'RetrievalError' if the HTTP call fails, or 'InvalidIAMError' if--- the specified IAM profile cannot be read.-fromProfileName :: (MonadIO m, MonadCatch m)-                => Manager-                -> Text-                -> m (Auth, Maybe Region)-fromProfileName m name = do-    auth <- getCredentials >>= start-    reg  <- getRegion-    return (auth, Just reg)-  where-    getCredentials :: (MonadIO m, MonadCatch m) => m AuthEnv-    getCredentials =-        try (metadata m (IAM . SecurityCredentials $ Just name)) >>=-            handleErr (eitherDecode' . LBS8.fromStrict) invalidIAMErr--    getRegion :: (MonadIO m, MonadCatch m) => m Region-    getRegion =-       try (identity m) >>=-           handleErr (fmap _region) invalidIdentityErr--    handleErr _ _ (Left  e) = throwM (RetrievalError e)-    handleErr f g (Right x) = either (throwM . g) return (f x)--    invalidIAMErr = InvalidIAMError-        . mappend ("Error parsing IAM profile '" <> name <> "' ")-        . Text.pack--    invalidIdentityErr = InvalidIAMError-        . mappend "Error parsing Instance Identity Document "-        . Text.pack--    start :: MonadIO m => AuthEnv -> m Auth-    start !a = liftIO $-        case _authExpiry a of-            Nothing -> return (Auth a)-            Just x  -> do-                r <- newIORef a-                p <- myThreadId-                s <- timer r p x-                return (Ref s r)--    timer :: IORef AuthEnv -> ThreadId -> UTCTime -> IO ThreadId-    timer !r !p !x = forkIO $ do-        s <- myThreadId-        w <- mkWeakIORef r (killThread s)-        loop w p x--    loop :: Weak (IORef AuthEnv) -> ThreadId -> UTCTime -> IO ()-    loop w !p !x = do-        diff x <$> getCurrentTime >>= threadDelay-        env <- try getCredentials-        case env of-            Left   e -> throwTo p (RetrievalError e)-            Right !a -> do-                 mr <- deRefWeak w-                 case mr of-                     Nothing -> return ()-                     Just  r -> do-                         atomicWriteIORef r a-                         maybe (return ()) (loop w p) (_authExpiry a)--    diff !x !y = (* 1000000) $ if n > 0 then n else 1-      where-        !n = truncate (diffUTCTime x y) - 60
− src/Network/AWS/Data.hs
@@ -1,34 +0,0 @@--- |--- Module      : Network.AWS.Data--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : provisional--- Portability : non-portable (GHC extensions)------ Re-exports some of the underlying textual and byte serialisation mechanisms--- for convenience.------ Many of the AWS identifiers like S3's 'ObjectVersionId' or 'ETag',--- as well as any nullary sum types such as 'Network.AWS.Region' have 'ToText'--- and 'ToByteString' instances, making it convenient to use the type classes--- to convert a value to its textual representation.-module Network.AWS.Data-    (-    -- * Text-      FromText     (..)-    , fromText-    , fromTextError-    , takeLowerText-    , ToText       (..)--    -- * ByteString-    , ToByteString (..)--    -- * Log Messages-    , ToLog        (..)-    ) where--import           Network.AWS.Data.ByteString-import           Network.AWS.Data.Log-import           Network.AWS.Data.Text
− src/Network/AWS/EC2/Metadata.hs
@@ -1,461 +0,0 @@-{-# LANGUAGE BangPatterns       #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts   #-}-{-# LANGUAGE LambdaCase         #-}-{-# LANGUAGE OverloadedStrings  #-}-{-# LANGUAGE RecordWildCards    #-}---- |--- Module      : Network.AWS.EC2.Metadata--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : provisional--- Portability : non-portable (GHC extensions)------ This module contains functions for retrieving various EC2 metadata from an--- instance's local metadata endpoint using 'MonadIO' and not one of the AWS--- specific transformers.------ It is intended to be used when you need to make metadata calls prior to--- initialisation of the 'Network.AWS.Env.Env'.-module Network.AWS.EC2.Metadata-    (-    -- * EC2 Instance Check-      isEC2--    -- * Retrieving Instance Data-    , dynamic-    , metadata-    , userdata-    , identity--    -- ** Path Constructors-    , Dynamic          (..)-    , Metadata         (..)-    , Mapping          (..)-    , Info             (..)-    , Interface        (..)--    -- ** Identity Document-    , IdentityDocument (..)--    -- *** Lenses-    , devpayProductCodes-    , billingProducts-    , version-    , privateIp-    , availabilityZone-    , region-    , instanceId-    , instanceType-    , accountId-    , imageId-    , kernelId-    , ramdiskId-    , architecture-    , pendingTime-    ) where--import           Control.Monad-import           Control.Monad.Catch-import           Control.Monad.IO.Class-import qualified Data.ByteString.Char8  as BS8-import qualified Data.ByteString.Lazy   as LBS-import           Data.Monoid-import qualified Data.Text              as Text-import           Network.AWS.Data.JSON-import           Network.AWS.Data.Time-import           Network.AWS.Lens       (Lens', lens, mapping)-import           Network.AWS.Prelude    hiding (request)-import           Network.HTTP.Conduit--data Dynamic-    = FWS-    -- ^ Value showing whether the customer has enabled detailed one-minute-    -- monitoring in CloudWatch.-    ---    -- Valid values: enabled | disabled.-    | Document-    -- ^ JSON containing instance attributes, such as instance-id,-    -- private IP address, etc.-    -- /See:/ 'identity', 'InstanceDocument'.-    | PKCS7-    -- ^ Used to verify the document's authenticity and content against the-    -- signature.-    | Signature-      deriving (Eq, Ord, Show, Typeable)--instance ToText Dynamic where-    toText = \case-       FWS       -> "dynamic/fws/instance-monitoring"-       Document  -> "dynamic/instance-identity/document"-       PKCS7     -> "dynamic/instance-identity/pkcs7"-       Signature -> "dynamic/instance-identity/signature"--data Metadata-    = AMIId-    -- ^ The AMI ID used to launch the instance.-    | AMILaunchIndex-    -- ^ If you started more than one instance at the same time, this value-    -- indicates the order in which the instance was launched.-    -- The value of the first instance launched is 0.-    | AMIManifestPath-    -- ^ The path to the AMI's manifest file in Amazon S3.-    -- If you used an Amazon EBS-backed AMI to launch the instance,-    -- the returned result is unknown.-    | AncestorAMIIds-    -- ^ The AMI IDs of any instances that were rebundled to create this AMI.-    -- This value will only exist if the AMI manifest file contained an-    -- ancestor-amis key.-    | BlockDevice !Mapping-    -- ^ See: 'Mapping'-    | Hostname-    -- ^ The private hostname of the instance. In cases where multiple network-    -- interfaces are present, this refers to the eth0 device-    -- (the device for which the device number is 0).-    | IAM !Info-    -- ^ See: 'Info'-    | InstanceAction-    -- ^ Notifies the instance that it should reboot in preparation for bundling.-    -- Valid values: none | shutdown | bundle-pending.-    | InstanceId-    -- ^ The ID of this instance.-    | InstanceType-    -- ^ The type of instance.-    ---    -- See: @InstanceType@-    | KernelId-    -- ^ The ID of the kernel launched with this instance, if applicable.-    | LocalHostname-    -- ^ The private DNS hostname of the instance. In cases where multiple-    -- network interfaces are present, this refers to the eth0 device-    -- (the device for which the device number is 0).-    | LocalIPV4-    -- ^ The private IP address of the instance. In cases where multiple network-    -- interfaces are present, this refers to the eth0 device-    -- (the device for which the device number is 0).-    | MAC-    -- ^ The instance's media access control (MAC) address. In cases where-    -- multiple network interfaces are present, this refers to the eth0 device-    -- (the device for which the device number is 0).-    | Network !Text !Interface-    -- ^ See: 'Interface'-    | AvailabilityZone-    -- ^ The Availability Zone in which the instance launched.-    | ProductCodes-    -- ^ Product codes associated with the instance, if any.-    | PublicHostname-    -- ^ The instance's public DNS. If the instance is in a VPC, this category-    -- is only returned if the enableDnsHostnames attribute is set to true.-    -- For more information, see Using DNS with Your VPC.-    | PublicIPV4-    -- ^ The public IP address. If an Elastic IP address is associated with the-    -- instance, the value returned is the Elastic IP address.-    | OpenSSHKey-    -- ^ Public key. Only available if supplied at instance launch time.-    | RAMDiskId-    -- ^ The ID of the RAM disk specified at launch time, if applicable.-    | ReservationId-    -- ^ ID of the reservation.-    | SecurityGroups-    -- ^ The names of the security groups applied to the instance.-      deriving (Eq, Ord, Show, Typeable)--instance ToText Metadata where-    toText = \case-        AMIId            -> "meta-data/ami-id"-        AMILaunchIndex   -> "meta-data/ami-launch-index"-        AMIManifestPath  -> "meta-data/ami-manifest-path"-        AncestorAMIIds   -> "meta-data/ancestor-ami-ids"-        BlockDevice m    -> "meta-data/block-device-mapping/" <> toText m-        Hostname         -> "meta-data/hostname"-        IAM m            -> "meta-data/iam/" <> toText m-        InstanceAction   -> "meta-data/instance-action"-        InstanceId       -> "meta-data/instance-id"-        InstanceType     -> "meta-data/instance-type"-        KernelId         -> "meta-data/kernel-id"-        LocalHostname    -> "meta-data/local-hostname"-        LocalIPV4        -> "meta-data/local-ipv4"-        MAC              -> "meta-data/mac"-        Network n m      -> "meta-data/network/interfaces/macs/" <> toText n <> "/" <> toText m-        AvailabilityZone -> "meta-data/placement/availability-zone"-        ProductCodes     -> "meta-data/product-codes"-        PublicHostname   -> "meta-data/public-hostname"-        PublicIPV4       -> "meta-data/public-ipv4"-        OpenSSHKey       -> "meta-data/public-keys/0/openssh-key"-        RAMDiskId        -> "meta-data/ramdisk-id"-        ReservationId    -> "meta-data/reservation-id"-        SecurityGroups   -> "meta-data/security-groups"--data Mapping-    = AMI-    -- ^ The virtual device that contains the root/boot file system.-    | EBS !Int-    -- ^ The virtual devices associated with Amazon EBS volumes, if present.-    -- This value is only available in metadata if it is present at launch time.-    -- The N indicates the index of the Amazon EBS volume (such as ebs1 or ebs2).-    | Ephemeral !Int-    -- ^ The virtual devices associated with ephemeral devices, if present.-    -- The N indicates the index of the ephemeral volume.-    | Root-    -- ^ The virtual devices or partitions associated with the root devices,-    -- or partitions on the virtual device, where the root (/ or C:) file system-    -- is associated with the given instance.-    | Swap-    -- ^ The virtual devices associated with swap. Not always present.-      deriving (Eq, Ord, Show, Typeable)--instance ToText Mapping where-    toText = \case-        AMI         -> "ami"-        EBS       n -> "ebs"       <> toText n-        Ephemeral n -> "ephemeral" <> toText n-        Root        -> "root"-        Swap        -> "root"--data Interface-    = IDeviceNumber-    -- ^ The device number associated with that interface. Each interface must-    -- have a unique device number. The device number serves as a hint to device-    -- naming in the instance; for example, device-number is 2 for the eth2 device.-    | IIPV4Associations !Text-    -- ^ The private IPv4 addresses that are associated with each public-ip-    -- address and assigned to that interface.-    | ILocalHostname-    -- ^ The interface's local hostname.-    | ILocalIPV4s-    -- ^ The private IP addresses associated with the interface.-    | IMAC-    -- ^ The instance's MAC address.-    | IOwnerId-    -- ^ The ID of the owner of the network interface. In multiple-interface-    -- environments, an interface can be attached by a third party, such as-    -- Elastic Load Balancing. Traffic on an interface is always billed to-    -- the interface owner.-    | IPublicHostname-    -- ^ The interface's public DNS. If the instance is in a VPC, this category-    -- is only returned if the enableDnsHostnames attribute is set to true.-    -- For more information, see Using DNS with Your VPC.-    | IPublicIPV4s-    -- ^ The Elastic IP addresses associated with the interface. There may be-    -- multiple IP addresses on an instance.-    | ISecurityGroups-    -- ^ Security groups to which the network interface belongs. Returned only-    -- for instances launched into a VPC.-    | ISecurityGroupIds-    -- ^ IDs of the security groups to which the network interface belongs.-    -- Returned only for instances launched into a VPC. For more information on-    -- security groups in the EC2-VPC platform, see Security Groups for Your VPC.-    | ISubnetId-    -- ^ The ID of the subnet in which the interface resides. Returned only for-    -- instances launched into a VPC.-    | ISubnetIPV4_CIDRBlock-    -- ^ The CIDR block of the subnet in which the interface resides. Returned-    -- only for instances launched into a VPC.-    | IVPCId-    -- ^ The ID of the VPC in which the interface resides. Returned only for-    -- instances launched into a VPC.-    | IVPCIPV4_CIDRBlock-    -- ^ The CIDR block of the VPC in which the interface resides. Returned only-    -- for instances launched into a VPC.-      deriving (Eq, Ord, Show, Typeable)--instance ToText Interface where-    toText = \case-        IDeviceNumber         -> "device-number"-        IIPV4Associations ip  -> "ipv4-associations/" <> toText ip-        ILocalHostname        -> "local-hostname"-        ILocalIPV4s           -> "local-ipv4s"-        IMAC                  -> "mac"-        IOwnerId              -> "owner-id"-        IPublicHostname       -> "public-hostname"-        IPublicIPV4s          -> "public-ipv4s"-        ISecurityGroups       -> "security-groups"-        ISecurityGroupIds     -> "security-group-ids"-        ISubnetId             -> "subnet-id"-        ISubnetIPV4_CIDRBlock -> "subnet-ipv4-cidr-block"-        IVPCId                -> "vpc-id"-        IVPCIPV4_CIDRBlock    -> "vpc-ipv4-cidr-block"--data Info-    = Info'-    -- ^ Returns information about the last time the instance profile was updated,-    -- including the instance's LastUpdated date, InstanceProfileArn,-    -- and InstanceProfileId.-    | SecurityCredentials (Maybe Text)-    -- ^ Where role-name is the name of the IAM role associated with the instance.-    -- Returns the temporary security credentials.-    ---    -- See: 'Auth' for JSON deserialisation.-      deriving (Eq, Ord, Show, Typeable)--instance ToText Info where-    toText = \case-        Info'                 -> "info"-        SecurityCredentials r -> "security-credentials/" <> maybe mempty toText r--latest :: Text-latest = "http://169.254.169.254/latest/"---- | Test whether the underlying host is running on EC2 by--- making an HTTP request to @http://instance-data/latest@.-isEC2 :: MonadIO m => Manager -> m Bool-isEC2 m = liftIO (req `catch` err)-  where-    req = do-        !_ <- request m "http://instance-data/latest"-        return True--    err :: HttpException -> IO Bool-    err = const (return False)---- | Retrieve the specified 'Dynamic' data.------ Throws 'HttpException' if HTTP communication fails.-dynamic :: (MonadIO m, MonadThrow m) => Manager -> Dynamic -> m ByteString-dynamic m = get m . mappend latest . toText---- | Retrieve the specified 'Metadata'.------ Throws 'HttpException' if HTTP communication fails.-metadata :: (MonadIO m, MonadThrow m) => Manager -> Metadata -> m ByteString-metadata m = get m . mappend latest . toText---- | Retrieve the user data. Returns 'Nothing' if no user data is assigned--- to the instance.------ Throws 'HttpException' if HTTP communication fails.-userdata :: (MonadIO m, MonadCatch m) => Manager -> m (Maybe ByteString)-userdata m = do-    x <- try $ get m (latest <> "user-data")-    case x of-        Left (HttpExceptionRequest _ (StatusCodeException rs _))-            | fromEnum (responseStatus rs) == 404-                -> return Nothing-        Left  e -> throwM e-        Right b -> return (Just b)---- | Represents an instance's identity document.------ /Note:/ Fields such as '_instanceType' are represented as unparsed 'Text' and--- will need to be manually parsed using 'fromText' when the relevant types--- from a library such as "Network.AWS.EC2" are brought into scope.-data IdentityDocument = IdentityDocument-    { _devpayProductCodes :: Maybe Text-    , _billingProducts    :: Maybe Text-    , _version            :: Maybe Text-    , _privateIp          :: Maybe Text-    , _availabilityZone   :: Text-    , _region             :: !Region-    , _instanceId         :: Text-    , _instanceType       :: Text-    , _accountId          :: Text-    , _imageId            :: Maybe Text-    , _kernelId           :: Maybe Text-    , _ramdiskId          :: Maybe Text-    , _architecture       :: Maybe Text-    , _pendingTime        :: Maybe ISO8601-    } deriving (Eq, Show)--devpayProductCodes :: Lens' IdentityDocument (Maybe Text)-devpayProductCodes = lens _devpayProductCodes (\s a -> s { _devpayProductCodes = a })--billingProducts :: Lens' IdentityDocument (Maybe Text)-billingProducts = lens _billingProducts (\s a -> s { _billingProducts = a })--version :: Lens' IdentityDocument (Maybe Text)-version = lens _version (\s a -> s { _version = a })--privateIp :: Lens' IdentityDocument (Maybe Text)-privateIp = lens _privateIp (\s a -> s { _privateIp = a })--availabilityZone :: Lens' IdentityDocument Text-availabilityZone = lens _availabilityZone (\s a -> s { _availabilityZone = a })--region :: Lens' IdentityDocument Region-region = lens _region (\s a -> s { _region = a })--instanceId :: Lens' IdentityDocument Text-instanceId = lens _instanceId (\s a -> s { _instanceId = a })--instanceType :: Lens' IdentityDocument Text-instanceType = lens _instanceType (\s a -> s { _instanceType = a })--accountId :: Lens' IdentityDocument Text-accountId = lens _accountId (\s a -> s { _accountId = a })--imageId :: Lens' IdentityDocument (Maybe Text)-imageId = lens _imageId (\s a -> s { _imageId = a })--kernelId :: Lens' IdentityDocument (Maybe Text)-kernelId = lens _kernelId (\s a -> s { _kernelId = a })--ramdiskId :: Lens' IdentityDocument (Maybe Text)-ramdiskId = lens _ramdiskId (\s a -> s { _ramdiskId = a })--architecture :: Lens' IdentityDocument (Maybe Text)-architecture = lens _architecture (\s a -> s { _architecture = a })--pendingTime :: Lens' IdentityDocument (Maybe UTCTime)-pendingTime = lens _pendingTime (\s a -> s { _pendingTime = a }) . mapping _Time--instance FromJSON IdentityDocument where-    parseJSON = withObject "dynamic/instance-identity/document" $ \o -> do-            _devpayProductCodes <- o .:? "devpayProductCodes"-            _billingProducts    <- o .:? "billingProducts"-            _privateIp          <- o .:? "privateIp"-            _version            <- o .:? "version"-            _availabilityZone   <- o .:  "availabilityZone"-            _region             <- o .:  "region"-            _instanceId         <- o .:  "instanceId"-            _instanceType       <- o .:  "instanceType"-            _accountId          <- o .:  "accountId"-            _imageId            <- o .:? "imageId"-            _kernelId           <- o .:? "kernelId"-            _ramdiskId          <- o .:? "ramdiskId"-            _architecture       <- o .:? "architecture"-            _pendingTime        <- o .:? "pendingTime"-            pure IdentityDocument{..}--instance ToJSON IdentityDocument where-    toJSON IdentityDocument{..} =-        object-            [ "devpayProductCodes" .= _devpayProductCodes-            , "billingProducts"    .= _billingProducts-            , "privateIp"          .= _privateIp-            , "version"            .= _version-            , "availabilityZone"   .= _availabilityZone-            , "region"             .= _region-            , "instanceId"         .= _instanceId-            , "instanceType"       .= _instanceType-            , "accountId"          .= _accountId-            , "imageId"            .= _imageId-            , "kernelId"           .= _kernelId-            , "ramdiskId"          .= _ramdiskId-            , "architecture"       .= _architecture-            ]---- | Retrieve the instance's identity document, detailing various EC2 metadata.------ You can alternatively retrieve the raw unparsed identity document by using--- 'dynamic' and the 'Document' path.------ /See:/ <http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html AWS Instance Identity Documents>.-identity :: (MonadIO m, MonadThrow m)-         => Manager-         -> m (Either String IdentityDocument)-identity m = (eitherDecode . LBS.fromStrict) `liftM` dynamic m Document--get :: (MonadIO m, MonadThrow m) => Manager -> Text -> m ByteString-get m url = liftIO (strip `liftM` request m url)-  where-    strip bs-        | BS8.isSuffixOf "\n" bs = BS8.init bs-        | otherwise              = bs--request :: Manager -> Text -> IO ByteString-request m url = do-    rq <- parseUrlThrow (Text.unpack url)-    rs <- httpLbs rq m-    return . LBS.toStrict $ responseBody rs
− src/Network/AWS/Env.hs
@@ -1,227 +0,0 @@-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE ViewPatterns  #-}-{-# LANGUAGE LambdaCase        #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes        #-}-{-# LANGUAGE RecordWildCards   #-}---- |--- Module      : Network.AWS.Env--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : provisional--- Portability : non-portable (GHC extensions)------ Environment and AWS specific configuration for the--- 'Network.AWS.AWS' and 'Control.Monad.Trans.AWS.AWST' monads.-module Network.AWS.Env-    (-    -- * Creating the Environment-      newEnv-    , newEnvWith--    , Env      (..)-    , HasEnv   (..)--    -- * Overriding Default Configuration-    , override-    , configure--    -- * Scoped Actions-    , reconfigure-    , within-    , once-    , timeout--    -- * Retry HTTP Exceptions-    , retryConnectionFailure-    ) where--import Data.Maybe (fromMaybe)-import           Control.Applicative-import           Control.Monad.Catch-import           Control.Monad.IO.Class-import           Control.Monad.Reader-import           Data.Function               (on)-import           Data.IORef-import           Data.Monoid-import           Network.AWS.Auth-import           Network.AWS.Internal.Logger-import           Network.AWS.Lens            (Getter, Lens')-import           Network.AWS.Lens            (lens, to)-import           Network.AWS.Lens            ((.~), (<>~), (?~))-import           Network.AWS.Types-import           Network.HTTP.Conduit---- | The environment containing the parameters required to make AWS requests.-data Env = Env-    { _envRegion     :: !Region-    , _envLogger     :: !Logger-    , _envRetryCheck :: !(Int -> HttpException -> Bool)-    , _envOverride   :: !(Dual (Endo Service))-    , _envManager    :: !Manager-    , _envEC2        :: !(IORef (Maybe Bool))-    , _envAuth       :: !Auth-    }---- Note: The strictness annotations aobe are applied to ensure--- total field initialisation.--class HasEnv a where-    environment   :: Lens' a Env-    {-# MINIMAL environment #-}--    -- | The current region.-    envRegion     :: Lens' a Region--    -- | The function used to output log messages.-    envLogger     :: Lens' a Logger--    -- | The function used to determine if an 'HttpException' should be retried.-    envRetryCheck :: Lens' a (Int -> HttpException -> Bool)--    -- | The currently applied overrides to all 'Service' configuration.-    envOverride   :: Lens' a (Dual (Endo Service))--    -- | The 'Manager' used to create and manage open HTTP connections.-    envManager    :: Lens' a Manager--    -- | The credentials used to sign requests for authentication with AWS.-    envAuth       :: Lens' a Auth--    -- | A memoised predicate for whether the underlying host is an EC2 instance.-    envEC2        :: Getter a (IORef (Maybe Bool))--    envRegion     = environment . lens _envRegion     (\s a -> s { _envRegion     = a })-    envLogger     = environment . lens _envLogger     (\s a -> s { _envLogger     = a })-    envRetryCheck = environment . lens _envRetryCheck (\s a -> s { _envRetryCheck = a })-    envOverride   = environment . lens _envOverride   (\s a -> s { _envOverride   = a })-    envManager    = environment . lens _envManager    (\s a -> s { _envManager    = a })-    envAuth       = environment . lens _envAuth       (\s a -> s { _envAuth       = a })-    envEC2        = environment . to _envEC2--instance HasEnv Env where-    environment = id--instance ToLog Env where-    build Env{..} = b <> "\n" <> build _envAuth-      where-        b = buildLines-            [ "[Amazonka Env] {"-            , "  region = " <> build _envRegion-            , "}"-            ]---- | Provide a function which will be added to the existing stack--- of overrides applied to all service configuration.------ To override a specific service, it's suggested you use--- either 'configure' or 'reconfigure' with a modified version of the default--- service, such as @Network.AWS.DynamoDB.dynamoDB@.-override :: HasEnv a => (Service -> Service) -> a -> a-override f = envOverride <>~ Dual (Endo f)---- | Configure a specific service. All requests belonging to the--- supplied service will use this configuration instead of the default.------ It's suggested you use a modified version of the default service, such--- as @Network.AWS.DynamoDB.dynamoDB@.------ /See:/ 'reconfigure'.-configure :: HasEnv a => Service -> a -> a-configure s = override f-  where-    f x | on (==) _svcAbbrev s x = s-        | otherwise              = x---- | Scope an action such that all requests belonging to the supplied service--- will use this configuration instead of the default.------ It's suggested you use a modified version of the default service, such--- as @Network.AWS.DynamoDB.dynamoDB@.------ /See:/ 'configure'.-reconfigure :: (MonadReader r m, HasEnv r) => Service -> m a -> m a-reconfigure = local . configure---- | Scope an action within the specific 'Region'.-within :: (MonadReader r m, HasEnv r) => Region -> m a -> m a-within r = local (envRegion .~ r)---- | Scope an action such that any retry logic for the 'Service' is--- ignored and any requests will at most be sent once.-once :: (MonadReader r m, HasEnv r) => m a -> m a-once = local (override (serviceRetry . retryAttempts .~ 0))---- | Scope an action such that any HTTP response will use this timeout value.------ Default timeouts are chosen by considering:------ * This 'timeout', if set.------ * The related 'Service' timeout for the sent request if set. (Usually 70s)------ * The 'envManager' timeout if set.------ * The default 'ClientRequest' timeout. (Approximately 30s)-timeout :: (MonadReader r m, HasEnv r) => Seconds -> m a -> m a-timeout s = local (override (serviceTimeout ?~ s))---- | Creates a new environment with a new 'Manager' without debug logging--- and uses 'getAuth' to expand/discover the supplied 'Credentials'.--- Lenses from 'HasEnv' can be used to further configure the resulting 'Env'.------ /Since:/ @1.5.0@ - The region is now retrieved from the @AWS_REGION@ environment--- variable (identical to official SDKs), or defaults to @us-east-1@.--- You can override the 'Env' region by using 'envRegion', or the current operation's--- region by using 'within'.------ /Since:/ @1.3.6@ - The default logic for retrying 'HttpException's now uses--- 'retryConnectionFailure' to retry specific connection failure conditions up to 3 times.--- Previously only service specific errors were automatically retried.--- This can be reverted to the old behaviour by resetting the 'Env' using--- 'envRetryCheck' lens to @(\\_ _ -> False)@.------ Throws 'AuthError' when environment variables or IAM profiles cannot be read.------ /See:/ 'newEnvWith'.-newEnv :: (Applicative m, MonadIO m, MonadCatch m)-       => Credentials -- ^ Credential discovery mechanism.-       -> m Env-newEnv c =-    liftIO (newManager conduitManagerSettings)-        >>= newEnvWith c Nothing---- | /See:/ 'newEnv'------ The 'Maybe' 'Bool' parameter is used by the EC2 instance check. By passing a--- value of 'Nothing', the check will be performed. 'Just' 'True' would cause--- the check to be skipped and the host treated as an EC2 instance.------ Throws 'AuthError' when environment variables or IAM profiles cannot be read.-newEnvWith :: (Applicative m, MonadIO m, MonadCatch m)-           => Credentials -- ^ Credential discovery mechanism.-           -> Maybe Bool  -- ^ Preload the EC2 instance check.-           -> Manager-           -> m Env-newEnvWith c p m = do-    (a, fromMaybe NorthVirginia -> r) <- getAuth m c-    Env r (\_ _ -> pure ()) (retryConnectionFailure 3) mempty m-        <$> liftIO (newIORef p)-        <*> pure a---- | Retry the subset of transport specific errors encompassing connection--- failure up to the specific number of times.-retryConnectionFailure :: Int -> Int -> HttpException -> Bool-retryConnectionFailure _     _ InvalidUrlException {}      = False-retryConnectionFailure limit n (HttpExceptionRequest _ ex)-    | n >= limit = False-    | otherwise  =-        case ex of-            NoResponseDataReceived -> True-            ConnectionTimeout      -> True-            ConnectionClosed       -> True-            ConnectionFailure {}   -> True-            InternalException {}   -> True-            _                      -> False
− src/Network/AWS/Internal/Body.hs
@@ -1,119 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}---- |--- Module      : Network.AWS.Internal.Body--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : provisional--- Portability : non-portable (GHC extensions)----module Network.AWS.Internal.Body where--import           Control.Applicative-import           Control.Monad-import           Control.Monad.IO.Class-import           Control.Monad.Morph-import           Control.Monad.Trans.Resource-import qualified Data.ByteString              as BS-import           Data.Conduit-import qualified Data.Conduit.Binary          as Conduit-import           Network.AWS.Prelude-import           System.IO---- | Convenience function for obtaining the size of a file.-getFileSize :: MonadIO m => FilePath -> m Integer-getFileSize f = liftIO (withBinaryFile f ReadMode hFileSize)---- | Connect a 'Sink' to a response stream.-sinkBody :: MonadResource m => RsBody -> Sink ByteString m a -> m a-sinkBody (RsBody s) sink = hoist liftResourceT s $$+- sink---- | Construct a 'HashedBody' from a 'FilePath', calculating the 'SHA256' hash--- and file size.------ /Note:/ While this function will perform in constant space, it will enumerate the--- entirety of the file contents _twice_. Firstly to calculate the SHA256 and--- lastly to stream the contents to the socket during sending.------ /See:/ 'ToHashedBody'.-hashedFile :: MonadIO m => FilePath -> m HashedBody-hashedFile f = liftIO $ HashedStream-    <$> runResourceT (Conduit.sourceFile f $$ sinkSHA256)-    <*> getFileSize f-    <*> pure (Conduit.sourceFile f)---- | Construct a 'HashedBody' from a source, manually specifying the--- 'SHA256' hash and file size.------ /See:/ 'ToHashedBody'.-hashedBody :: Digest SHA256-           -> Integer-           -> Source (ResourceT IO) ByteString-           -> HashedBody-hashedBody h n = HashedStream h n---- | Something something.------ Will intelligently revert to 'HashedBody' if the file is smaller than the--- specified 'ChunkSize'.------ Add note about how it selects chunk size.------ /See:/ 'ToBody'.-chunkedFile :: MonadIO m => ChunkSize -> FilePath -> m RqBody-chunkedFile c f = do-    n <- getFileSize f-    if n > toInteger c-        then return $ unsafeChunkedBody c n (sourceFileChunks c f)-        else Hashed `liftM` hashedFile f---- | Something something.------ Marked as unsafe because it does nothing to enforce the chunk size.--- Typically for conduit 'IO' functions, it's whatever ByteString's--- 'defaultBufferSize' is, around 32 KB. If the chunk size is less than 8 KB,--- the request will error. 64 KB or higher chunk size is recommended for--- performance reasons.------ Note that it will always create a chunked body even if the request--- is too small.------ /See:/ 'ToBody'.-unsafeChunkedBody :: ChunkSize-                  -> Integer-                  -> Source (ResourceT IO) ByteString-                  -> RqBody-unsafeChunkedBody c n = Chunked . ChunkedBody c n---- Uses hGet with a specific buffer size, instead of hGetSome.-sourceFileChunks :: MonadResource m-                 => ChunkSize-                 -> FilePath-                 -> Source m ByteString-sourceFileChunks (ChunkSize sz) f =-    bracketP (openBinaryFile f ReadMode) hClose go-  where-    go h = do-        bs <- liftIO (BS.hGet h sz)-        unless (BS.null bs) $ do-            yield bs-            go h---- | Incrementally calculate a 'MD5' 'Digest'.-sinkMD5 :: Monad m => Consumer ByteString m (Digest MD5)-sinkMD5 = sinkHash---- | Incrementally calculate a 'SHA256' 'Digest'.-sinkSHA256 :: Monad m => Consumer ByteString m (Digest SHA256)-sinkSHA256 = sinkHash---- | A cryptonite compatible incremental hash sink.-sinkHash :: (Monad m, HashAlgorithm a) => Consumer ByteString m (Digest a)-sinkHash = sink hashInit-  where-    sink ctx = do-        b <- await-        case b of-            Nothing -> return $! hashFinalize ctx-            Just bs -> sink $! hashUpdate ctx bs
− src/Network/AWS/Internal/HTTP.hs
@@ -1,169 +0,0 @@-{-# LANGUAGE BangPatterns      #-}-{-# LANGUAGE FlexibleContexts  #-}-{-# LANGUAGE LambdaCase        #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes        #-}-{-# LANGUAGE RecordWildCards   #-}-{-# LANGUAGE TypeFamilies      #-}-{-# LANGUAGE ViewPatterns      #-}---- |--- Module      : Network.AWS.Internal.HTTP--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : provisional--- Portability : non-portable (GHC extensions)----module Network.AWS.Internal.HTTP-    ( retrier-    , waiter-    ) where--import           Control.Arrow                (first)-import           Control.Monad-import           Control.Monad.Catch-import           Control.Monad.Reader-import           Control.Monad.Trans.Resource-import           Control.Retry-import           Data.List                    (intersperse)-import           Data.Monoid-import           Data.Proxy-import           Data.Time-import           Network.AWS.Env-import           Network.AWS.Internal.Logger-import           Network.AWS.Lens             ((%~), (&), (^.), (^?))-import           Network.AWS.Lens             (to, view, _Just)-import           Network.AWS.Prelude-import           Network.AWS.Waiter-import           Network.HTTP.Conduit         hiding (Proxy, Request, Response)--retrier :: ( MonadCatch m-           , MonadResource m-           , MonadReader r m-           , HasEnv r-           , AWSRequest a-           )-        => a-        -> m (Either Error (Response a))-retrier x = do-    e  <- view environment-    rq <- configured x-    retrying (policy rq) (check e rq) (\_ -> perform e rq)-  where-    policy rq = retryStream rq <> retryService (_rqService rq)--    check e rq s (Left r)-        | Just p <- r ^? transportErr, p = msg e "http_error" s >> return True-        | Just m <- r ^? serviceErr      = msg e m            s >> return True-      where-        transportErr = _TransportError . to (_envRetryCheck e (rsIterNumber s))-        serviceErr   = _ServiceError . to rc . _Just--        rc = rq ^. rqService . serviceRetry . retryCheck--    check _ _ _ _                          = return False--    msg :: MonadIO m => Env -> Text -> RetryStatus -> m ()-    msg e m s = logDebug (_envLogger e)-        . mconcat-        . intersperse " "-        $ [ "[Retry " <> build m <> "]"-          , "after"-          , build (rsIterNumber s + 1)-          , "attempts."-          ]--waiter :: ( MonadCatch m-          , MonadResource m-          , MonadReader r m-          , HasEnv r-          , AWSRequest a-          )-       => Wait a-       -> a-       -> m (Either Error Accept)-waiter w@Wait{..} x = do-   e@Env{..} <- view environment-   rq        <- configured x-   retrying policy (check _envLogger) (\_ -> result rq <$> perform e rq) >>= exit-  where-    policy = limitRetries _waitAttempts-          <> constantDelay (microseconds _waitDelay)--    check e n (a, _) = msg e n a >> return (retry a)-      where-        retry AcceptSuccess = False-        retry AcceptFailure = False-        retry AcceptRetry   = True--    result rq = first (fromMaybe AcceptRetry . accept w rq) . join (,)--    exit (AcceptSuccess, _) = return (Right AcceptSuccess)-    exit (_,        Left e) = return (Left e)-    exit (a,        _)      = return (Right a)--    msg l s a = logDebug l-        . mconcat-        . intersperse " "-        $ [ "[Await " <> build _waitName <> "]"-          , build a-          , "after"-          , build (rsIterNumber s + 1)-          , "attempts."-          ]---- | The 'Service' is configured + unwrapped at this point.-perform :: (MonadCatch m, MonadResource m, AWSRequest a)-        => Env-        -> Request a-        -> m (Either Error (Response a))-perform Env{..} x = catches go handlers-  where-    go = do-        t           <- liftIO getCurrentTime-        Signed m rq <--            withAuth _envAuth $ \a ->-                return $! rqSign x a _envRegion t--        logTrace _envLogger m  -- trace:Signing:Meta-        logDebug _envLogger rq -- debug:ClientRequest--        rs          <- liftResourceT (http rq _envManager)--        logDebug _envLogger rs -- debug:ClientResponse--        Right <$> response _envLogger (_rqService x) (p x) rs--    handlers =-        [ Handler $ err-        , Handler $ err . TransportError-        ]-      where-        err e = logError _envLogger e >> return (Left e)--    p :: Request a -> Proxy a-    p = const Proxy--configured :: (MonadReader r m, HasEnv r, AWSRequest a)-           => a-           -> m (Request a)-configured (request -> x) = do-    o <- view envOverride-    return $! x & rqService %~ appEndo (getDual o)--retryStream :: Request a -> RetryPolicy-retryStream x = RetryPolicyM (\_ -> return (listToMaybe [0 | not p]))-  where-    !p = isStreaming (_rqBody x)--retryService :: Service -> RetryPolicy-retryService s = limitRetries _retryAttempts <> RetryPolicyM (return . delay)-  where-    delay (rsIterNumber -> n)-        | n >= 0 = Just $ truncate (grow * 1000000)-        | otherwise = Nothing-      where-        grow = _retryBase * (fromIntegral _retryGrowth ^^ (n - 1))--    Exponential{..} = _svcRetry s
− src/Network/AWS/Internal/Logger.hs
@@ -1,57 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}---- |--- Module      : Network.AWS.Internal.Logger--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : provisional--- Portability : non-portable (GHC extensions)------ Types and functions for constructing loggers and emitting log messages.-module Network.AWS.Internal.Logger-    (-    -- * Constructing a Logger-      Logger-    , newLogger--    -- * Levels-    , LogLevel (..)-    , logError-    , logInfo-    , logDebug-    , logTrace--    -- * Building Messages-    , ToLog    (..)-    , buildLines-    ) where--import           Control.Monad-import           Control.Monad.IO.Class-import qualified Data.ByteString.Lazy.Builder as Build-import           Data.Monoid-import           Network.AWS.Data.Log-import           Network.AWS.Types-import           System.IO---- | This is a primitive logger which can be used to log builds to a 'Handle'.------ /Note:/ A more sophisticated logging library such as--- <http://hackage.haskell.org/package/tinylog tinylog> or--- <http://hackage.haskell.org/package/FastLogger fast-logger>--- should be used in production code.-newLogger :: MonadIO m => LogLevel -> Handle -> m Logger-newLogger x hd = liftIO $ do-    hSetBinaryMode hd True-    hSetBuffering  hd LineBuffering-    return $ \y b ->-        when (x >= y) $-            Build.hPutBuilder hd (b <> "\n")--logError, logInfo, logDebug, logTrace- :: (MonadIO m, ToLog a) => Logger -> a -> m ()-logError f = liftIO . f Error . build-logInfo  f = liftIO . f Info  . build-logDebug f = liftIO . f Debug . build-logTrace f = liftIO . f Trace . build
− src/Network/AWS/Presign.hs
@@ -1,65 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}---- |--- Module      : Network.AWS.Presign--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : provisional--- Portability : non-portable (GHC extensions)------ This module contains functions for presigning requests using 'MonadIO' and--- not one of the AWS specific transformers.------ It is intended for use directly with "Network.AWS.Auth" when only presigning--- and no other AWS actions are required.-module Network.AWS.Presign where--import           Control.Monad-import           Control.Monad.IO.Class-import           Network.AWS.Data.Time-import           Network.AWS.Lens       ((%~), (&))-import           Network.AWS.Prelude-import           Network.AWS.Request    (requestURL)-import           Network.AWS.Types---- | Presign an URL that is valid from the specified time until the--- number of seconds expiry has elapsed.------ /See:/ 'presign', 'presignWith'-presignURL :: (MonadIO m, AWSRequest a)-           => Auth-           -> Region-           -> UTCTime     -- ^ Signing time.-           -> Seconds     -- ^ Expiry time.-           -> a           -- ^ Request to presign.-           -> m ByteString-presignURL a r e ts = liftM requestURL . presign a r e ts---- | Presign an HTTP request that is valid from the specified time until the--- number of seconds expiry has elapsed.------ /See:/ 'presignWith'-presign :: (MonadIO m, AWSRequest a)-        => Auth-        -> Region-        -> UTCTime     -- ^ Signing time.-        -> Seconds     -- ^ Expiry time.-        -> a           -- ^ Request to presign.-        -> m ClientRequest-presign = presignWith id---- | A variant of 'presign' that allows modifying the default 'Service'--- definition used to configure the request.-presignWith :: (MonadIO m, AWSRequest a)-            => (Service -> Service) -- ^ Modify the default service configuration.-            -> Auth-            -> Region-            -> UTCTime              -- ^ Signing time.-            -> Seconds              -- ^ Expiry time.-            -> a                    -- ^ Request to presign.-            -> m ClientRequest-presignWith f a r ts ex x =-    withAuth a $ \ae ->-        return $! sgRequest $-            rqPresign ex (request x & rqService %~ f) ae r ts
− test/Main.hs
@@ -1,16 +0,0 @@--- Module      : Main--- Copyright   : (c) 2013-2016 Brendan Hay--- License     : Mozilla Public License, v. 2.0.--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>--- Stability   : experimental--- Portability : non-portable (GHC extensions)--module Main (main) where--import           Test.Tasty--main :: IO ()-main = defaultMain $-    testGroup "amazonka"-        [-        ]