├── src └── AWS │ ├── Core │ ├── Credentials.js │ ├── Credentials.purs │ ├── Client.purs │ ├── Types.purs │ └── Util.purs │ ├── Lambda │ ├── Lambda.js │ └── Lambda.purs │ ├── CostExplorer │ ├── CostExplorer.js │ ├── Types.purs │ └── CostExplorer.purs │ ├── CloudWatch │ ├── Cloudwatch.js │ ├── Types.purs │ └── Cloudwatch.purs │ ├── SecretsManager │ ├── SecretsManager.js │ └── SecretsManager.purs │ ├── KMS │ ├── KMS.js │ └── KMS.purs │ ├── SecurityTokenService │ ├── SecurityTokenService.js │ └── SecurityTokenService.purs │ ├── Pricing │ ├── Pricing.js │ ├── EC2 │ │ ├── Types.purs │ │ └── Utils.purs │ ├── ECS │ │ ├── Types.purs │ │ └── Utils.purs │ ├── Utils.purs │ ├── Types.purs │ └── Pricing.purs │ ├── DynamoDB │ ├── DynamoDb.js │ └── DynamoDb.purs │ ├── S3 │ ├── S3.js │ └── S3.purs │ ├── EC2 │ ├── EC2.js │ ├── Types.purs │ └── EC2.purs │ ├── ECS │ ├── ECS.js │ ├── Types.purs │ └── ECS.purs │ └── CloudWatchLogs │ ├── CloudwatchLogs.js │ └── CloudwatchLogs.purs ├── .gitignore ├── packages.dhall ├── package.json ├── CHANGELOG.md ├── spago.dhall ├── .github └── workflows │ └── main.yml ├── LICENSE ├── bower.json └── README.md /src/AWS/Core/Credentials.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | var AWS = require('aws-sdk') 4 | 5 | exports.newSharedIniFileCredentials = (params) => () => new AWS.SharedIniFileCredentials(params) 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bower_components/ 2 | /node_modules/ 3 | /.pulp-cache/ 4 | /output/ 5 | /generated-docs/ 6 | /.psc-package/ 7 | /.psc* 8 | /.purs* 9 | /.psa* 10 | /.spago 11 | *.psc-ide-port 12 | -------------------------------------------------------------------------------- /src/AWS/Core/Credentials.purs: -------------------------------------------------------------------------------- 1 | module AWS.Core.Credentials where 2 | 3 | import AWS.Core.Types (Credentials) 4 | import Effect (Effect) 5 | 6 | foreign import newSharedIniFileCredentials :: { profile :: String } -> Effect Credentials 7 | -------------------------------------------------------------------------------- /src/AWS/Lambda/Lambda.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | var AWS = require('aws-sdk') 4 | 5 | exports.newLambda = (params) => 6 | () => new AWS.Lambda(params) 7 | 8 | exports.invokeImpl = (lambda, params) => 9 | () => lambda.invoke(params).promise() 10 | -------------------------------------------------------------------------------- /packages.dhall: -------------------------------------------------------------------------------- 1 | let upstream = 2 | https://github.com/purescript/package-sets/releases/download/psc-0.14.2-20210613/packages.dhall sha256:64d7b5a1921e8458589add8a1499a1c82168e726a87fc4f958b3f8760cca2efe 3 | 4 | let overrides = {=} 5 | 6 | let additions = {=} 7 | 8 | in upstream // overrides // additions 9 | -------------------------------------------------------------------------------- /src/AWS/CostExplorer/CostExplorer.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const CostExplorer = require('aws-sdk/clients/costexplorer') 4 | 5 | exports.newCE = (params) => 6 | () => new CostExplorer(params) 7 | 8 | 9 | exports.getCostAndUsageImpl = (ce, params) => 10 | () => ce.getCostAndUsage(params).promise() 11 | -------------------------------------------------------------------------------- /src/AWS/CloudWatch/Cloudwatch.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const CloudWatch = require('aws-sdk/clients/cloudwatch') 4 | 5 | 6 | exports.newCloudWatch = (params) => 7 | () => new CloudWatch(params) 8 | 9 | exports.getMetricStatisticsImpl = (cw, p) => 10 | () => cw.getMetricStatistics(p).promise().then(JSON.stringify) 11 | -------------------------------------------------------------------------------- /src/AWS/SecretsManager/SecretsManager.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const SecretsManager = require('aws-sdk/clients/secretsmanager') 4 | 5 | exports.newSecretsManager = (params) => () => new SecretsManager(params) 6 | 7 | exports.getSecretValueImpl = (sm, params) => () => sm 8 | .getSecretValue(params) 9 | .promise() 10 | -------------------------------------------------------------------------------- /src/AWS/KMS/KMS.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const KMS = require('aws-sdk/clients/kms') 4 | 5 | exports.newKMS = (params) => () => new KMS(params) 6 | 7 | exports.encryptImpl = (kms, params) => () => kms 8 | .encrypt(params) 9 | .promise() 10 | 11 | exports.decryptImpl = (kms, params) => () => kms 12 | .decrypt(params) 13 | .promise() 14 | -------------------------------------------------------------------------------- /src/AWS/SecurityTokenService/SecurityTokenService.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const STS = require('aws-sdk/clients/sts') 4 | 5 | // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/STS.html 6 | exports.newSTS = (params) => () => new STS(params) 7 | 8 | exports.assumeRoleImpl = (sts, params) => 9 | () => sts.assumeRole(params).promise() 10 | 11 | -------------------------------------------------------------------------------- /src/AWS/Pricing/Pricing.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict" 3 | 4 | const Pricing = require('aws-sdk/clients/pricing') 5 | 6 | exports.newPricing = (params) => 7 | () => new Pricing(params) 8 | 9 | exports.getProductsImpl = (client, filters, serviceCode, token, max) => 10 | () => client.getProducts({ Filters: filters, ServiceCode: serviceCode, NextToken: token, MaxResults: max }).promise() 11 | -------------------------------------------------------------------------------- /src/AWS/DynamoDB/DynamoDb.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | var AWS = require('aws-sdk') 4 | 5 | exports.newDynamoDbClient = (params) => () => new AWS.DynamoDB(params) 6 | 7 | exports.getItemImpl = (db, params) => () => db.getItem(params).promise() 8 | 9 | exports.putItemImpl = (db, params) => () => db.putItem(params).promise() 10 | 11 | exports.createTableImpl = (db, params) => () => db.createTable(params).promise() 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "purescript-aws-sdk", 3 | "repository": "purescript-aws-sdk", 4 | "license": "MIT", 5 | "description": "Purescript wrapper for typescript API AWS-sdk", 6 | "version": "0.1.0", 7 | "devDependencies": { 8 | "bower": "^1.8.12", 9 | "pulp": "^15.0.0", 10 | "purescript": "^0.14.2", 11 | "purty": "^7.0.0", 12 | "spago": "^0.20.3" 13 | }, 14 | "dependencies": { 15 | "aws-sdk": "^2.1066.0" 16 | } 17 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v0.15.1 2 | - Cleanup of exports => internal datatypes are not visible anymore which may be a breaking change for some users 3 | 4 | # v0.15.0 5 | - Update to Purescript v0.14.0 6 | 7 | # v0.14.1 8 | ## General: 9 | - Added CHANGELOG.md file ;-) 10 | 11 | # v0.14.0 12 | ## CloudWatchLogs: 13 | - The parameter `nextToken` now needs to be specified when calling `describeLogStreams` or `describeLogGroups`. The response now also includes `nextToken`. 14 | -------------------------------------------------------------------------------- /src/AWS/S3/S3.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const S3 = require('aws-sdk/clients/s3') 4 | 5 | exports.newS3 = (params) => () => new S3(params) 6 | 7 | exports.getObjectImpl = (s3, params) => () => s3 8 | .getObject(params) 9 | .promise() 10 | 11 | exports.getSignedUrlImpl = (s3, operation, params) => () => s3 12 | .getSignedUrlPromise(operation, params) 13 | 14 | 15 | exports.createBucketImpl = (s3, bucket, config) => () => s3 16 | .createBucket({ Bucket: bucket, CreateBucketConfiguration: config }) 17 | .promise() 18 | 19 | exports.putBucketPolicyImpl = (s3, bucket, policy) => () => s3 20 | .putBucketPolicy({ Bucket: bucket, Policy: policy }) 21 | .promise() 22 | -------------------------------------------------------------------------------- /spago.dhall: -------------------------------------------------------------------------------- 1 | { name = "purescript-aws-sdk-basic" 2 | , dependencies = 3 | [ "aff" 4 | , "aff-promise" 5 | , "argonaut" 6 | , "argonaut-codecs" 7 | , "arrays" 8 | , "bifunctors" 9 | , "console" 10 | , "datetime" 11 | , "effect" 12 | , "either" 13 | , "exceptions" 14 | , "foreign-object" 15 | , "formatters" 16 | , "functions" 17 | , "integers" 18 | , "js-date" 19 | , "justifill" 20 | , "maybe" 21 | , "newtype" 22 | , "node-buffer" 23 | , "nullable" 24 | , "ordered-collections" 25 | , "prelude" 26 | , "record" 27 | , "transformers" 28 | , "tuples" 29 | , "unfoldable" 30 | ] 31 | , packages = ./packages.dhall 32 | , sources = [ "src/**/*.purs" ] 33 | , license = "MIT" 34 | , repository = "https://github.com/HivemindTechnologies/purescript-aws-sdk.git" 35 | } 36 | -------------------------------------------------------------------------------- /src/AWS/Pricing/EC2/Types.purs: -------------------------------------------------------------------------------- 1 | module AWS.Pricing.EC2.Types where 2 | 3 | import AWS.Pricing.Types (Terms) 4 | import Data.Either (Either) 5 | import Data.Maybe (Maybe) 6 | 7 | type GetEC2ProductsResponse 8 | = { formatVersion :: String 9 | , priceList :: Array (Either String EC2PriceList) 10 | , nextToken :: Maybe String 11 | } 12 | 13 | type EC2Attributes r 14 | = { instanceType :: String 15 | , instanceFamily :: String 16 | , operatingSystem :: String 17 | , vcpu :: String 18 | , servicename :: String 19 | | r 20 | } 21 | 22 | type EC2Product r 23 | = { attributes :: (Either String (EC2Attributes ())) | r } 24 | 25 | type EC2PriceList 26 | = { serviceCode :: String 27 | , version :: String 28 | , publicationDate :: String 29 | , product :: EC2Product () 30 | , terms :: Terms 31 | } 32 | -------------------------------------------------------------------------------- /src/AWS/EC2/EC2.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const EC2 = require('aws-sdk/clients/ec2') 4 | 5 | exports.newEC2 = (params) => 6 | () => new EC2(params) 7 | 8 | exports.describeInstancesImpl = (ec2, filters) => 9 | () => { 10 | if (filters.length == 0) { 11 | return ec2.describeInstances().promise() 12 | } 13 | else { 14 | return ec2.describeInstances({ Filters: filters }).promise() 15 | } 16 | } 17 | 18 | exports.describeTagsImpl = (ec2, filters) => 19 | () => ec2.describeTags({ Filters: filters }).promise() 20 | 21 | exports.describeInstanceAttributeImpl = (ec2, attribute, instanceId) => 22 | () => ec2.describeInstanceAttribute({ Attribute: attribute, InstanceId: instanceId }).promise() 23 | 24 | exports.describeInstanceTypesImpl = (ec2, instanceTypes) => 25 | () => ec2.describeInstanceTypes({ InstanceTypes: instanceTypes }).promise() -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the main branch 8 | push: 9 | branches: [ main ] 10 | pull_request: 11 | branches: [ main ] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | # This workflow contains a single job called "build" 19 | build: 20 | # The type of runner that the job will run on 21 | runs-on: ubuntu-latest 22 | 23 | # Steps represent a sequence of tasks that will be executed as part of the job 24 | steps: 25 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 26 | - uses: actions/checkout@v2 27 | 28 | - name: "build" 29 | run: "npm install && npx spago build" 30 | -------------------------------------------------------------------------------- /src/AWS/ECS/ECS.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const ECS = require('aws-sdk/clients/ecs') 4 | 5 | exports.newECS = (params) => 6 | () => new ECS(params) 7 | 8 | exports.listClustersImpl = (ecs) => 9 | () => ecs.listClusters().promise() 10 | 11 | exports.listTasksImpl = (ecs, clusterArn, containerInstanceArn) => 12 | () => ecs.listTasks({ cluster: clusterArn, containerInstance: containerInstanceArn }).promise() 13 | 14 | exports.listContainerInstancesImpl = (ecs, clusterArn) => 15 | () => ecs.listContainerInstances({ cluster: clusterArn }).promise() 16 | 17 | exports.describeClustersImpl = (ecs, clusterArns) => 18 | () => ecs.describeClusters({ clusters: clusterArns }).promise() 19 | 20 | exports.describeContainerInstancesImpl = (ecs, clusterArn, containerInstanceArns) => 21 | () => ecs.describeContainerInstances({ cluster: clusterArn, containerInstances: containerInstanceArns }).promise() 22 | 23 | exports.describeTasksImpl = (ecs, taskArns, clusterArn) => 24 | () => ecs.describeTasks({ tasks: taskArns, cluster: clusterArn }).promise() 25 | -------------------------------------------------------------------------------- /src/AWS/CloudWatchLogs/CloudwatchLogs.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const { CloudWatchLogs } = require('aws-sdk') 4 | 5 | exports.newCloudWatchLogs = (params) => 6 | () => new CloudWatchLogs(params) 7 | 8 | exports.describeLogGroupsImpl = (cw, params) => 9 | () => cw.describeLogGroups(params).promise() 10 | 11 | exports.describeLogStreamsImpl = (cw, params) => 12 | () => cw.describeLogStreams(params).promise() 13 | 14 | exports.putRetentionPolicyImpl = (cw, groupName, retention) => 15 | () => cw.putRetentionPolicy({ logGroupName: groupName, retentionInDays: retention }).promise() 16 | 17 | exports.deleteRetentionPolicyImpl = (cw, groupName) => 18 | () => cw.deleteRetentionPolicy({ logGroupName: groupName }).promise() 19 | 20 | exports.createExportTaskImpl = (cw, destination, from, groupName, to) => 21 | () => cw.createExportTask({ destination: destination, from: from, logGroupName: groupName, to: to }).promise() 22 | 23 | exports.listTagsLogGroupImpl = (cw, groupName) => 24 | () => cw.listTagsLogGroup({ logGroupName: groupName }).promise() 25 | -------------------------------------------------------------------------------- /src/AWS/Pricing/EC2/Utils.purs: -------------------------------------------------------------------------------- 1 | module AWS.Pricing.EC2.Utils where 2 | 3 | import Prelude 4 | import AWS.Core.Util (handleError) 5 | import AWS.Pricing.EC2.Types (EC2Attributes, EC2PriceList, EC2Product) 6 | import AWS.Pricing.Types (InternalPriceList, InternalProduct) 7 | import AWS.Pricing.Utils (toTerms) 8 | import Data.Argonaut (Json, decodeJson) 9 | import Data.Bifunctor (lmap, bimap) 10 | import Data.Either (Either) 11 | 12 | toEC2PriceList :: InternalPriceList -> EC2PriceList 13 | toEC2PriceList pl = 14 | { serviceCode: pl.serviceCode 15 | , version: pl.version 16 | , publicationDate: pl.publicationDate 17 | , product: toEC2Product pl.product 18 | , terms: toTerms pl.terms 19 | } 20 | 21 | toEC2Product :: InternalProduct -> EC2Product () 22 | toEC2Product internalProduct = 23 | { attributes: parseAttributes internalProduct.attributes 24 | } 25 | where 26 | parseAttributes :: Json -> Either String (EC2Attributes ()) 27 | parseAttributes = decodeJson <#> lmap handleError 28 | 29 | parseEC2PriceList :: Json -> Either String EC2PriceList 30 | parseEC2PriceList = decodeJson <#> bimap handleError toEC2PriceList 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Hivemind Technologies AG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "purescript-aws-sdk-basic", 3 | "license": [ 4 | "MIT" 5 | ], 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/HivemindTechnologies/purescript-aws-sdk.git" 9 | }, 10 | "ignore": [ 11 | "/bower_components/", 12 | "/node_modules/", 13 | "/.pulp-cache/", 14 | "/output/", 15 | "/generated-docs/", 16 | "/.psc-package/", 17 | "/.psc*", 18 | "/.purs*", 19 | "/.psa*", 20 | "/.spago", 21 | "*.psc-ide-port" 22 | ], 23 | "dependencies": { 24 | "purescript-aff-promise": "^v2.1.0", 25 | "purescript-argonaut": "^v8.0.0", 26 | "purescript-console": "^v5.0.0", 27 | "purescript-datetime": "^v5.0.0", 28 | "purescript-effect": "^v3.0.0", 29 | "purescript-foreign": "^v6.0.0", 30 | "purescript-formatters": "^v5.0.0", 31 | "purescript-js-date": "^v7.0.0", 32 | "purescript-justifill": "i-am-the-slime/purescript-justifill#^v0.2.0", 33 | "purescript-monad-control": "^v5.0.0", 34 | "purescript-node-buffer": "^v7.0.0", 35 | "purescript-nullable": "^v5.0.0", 36 | "purescript-numbers": "^v8.0.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/AWS/Core/Client.purs: -------------------------------------------------------------------------------- 1 | module AWS.Core.Client (makeDefaultClient, makeClientHelper) where 2 | 3 | import AWS.Core.Types 4 | import Data.Argonaut (class EncodeJson, Json, encodeJson) 5 | import Effect (Effect) 6 | import Justifill (justifill) 7 | import Justifill.Fillable (class FillableFields) 8 | import Justifill.Justifiable (class JustifiableFields) 9 | import Prelude ((>>>)) 10 | import Prim.Row (class Nub, class Union) 11 | import Prim.RowList (class RowToList) 12 | 13 | makeClientHelper :: 14 | forall additionalProps client. 15 | EncodeJson (BasicClientProps additionalProps) => 16 | (Json -> Effect client) -> BasicClientProps additionalProps -> Effect client 17 | makeClientHelper newClient = encodeJson >>> newClient 18 | 19 | makeDefaultClient :: 20 | forall additionalProps output input to toRL inputRL. 21 | Nub (BasicClientPropsR additionalProps) (BasicClientPropsR additionalProps) => 22 | RowToList to toRL => 23 | FillableFields toRL () to => 24 | Union 25 | output 26 | to 27 | (BasicClientPropsR additionalProps) => 28 | RowToList input inputRL => 29 | JustifiableFields inputRL input () output => 30 | Record input -> 31 | BasicClientProps additionalProps 32 | makeDefaultClient r = ((justifill r) :: BasicClientProps additionalProps) 33 | -------------------------------------------------------------------------------- /src/AWS/Pricing/ECS/Types.purs: -------------------------------------------------------------------------------- 1 | module AWS.Pricing.ECS.Types where 2 | 3 | import Prelude 4 | import AWS.Pricing.Types (Terms) 5 | import Data.Either (Either) 6 | import Data.Maybe (Maybe) 7 | 8 | type GetECSProductsResponse 9 | = { formatVersion :: String 10 | , priceList :: Array (Either String ECSPriceList) 11 | , nextToken :: Maybe String 12 | } 13 | 14 | type ECSAttributes r 15 | = { servicecode :: String 16 | , usagetype :: String 17 | , servicename :: String 18 | , operation :: String 19 | | r 20 | } 21 | 22 | type ECSProduct r 23 | = { attributes :: (Either String (ECSAttributes ())) | r } 24 | 25 | type ECSPriceList 26 | = { serviceCode :: String 27 | , version :: String 28 | , publicationDate :: String 29 | , product :: ECSProduct () 30 | , terms :: Terms 31 | } 32 | 33 | data ECSUsageType 34 | = EUC1FargateEphemeralStorageGBHours 35 | | EUC1FargateGBHours 36 | | EUC1FargatevCPUHoursperCPU 37 | | EUFargateEphemeralStorageGBHours 38 | | EUFargateGBHours 39 | | EUFargatevCPUHoursperCPU 40 | 41 | instance showECSUsageType :: Show ECSUsageType where 42 | show EUC1FargateEphemeralStorageGBHours = "EUC1-Fargate-EphemeralStorage-GB-Hours" 43 | show EUC1FargateGBHours = "EUC1-Fargate-GB-Hours" 44 | show EUC1FargatevCPUHoursperCPU = "EUC1-Fargate-vCPU-Hours:perCPU" 45 | show EUFargateEphemeralStorageGBHours = "EU-Fargate-EphemeralStorage-GB-Hours" 46 | show EUFargateGBHours = "EU-Fargate-GB-Hours" 47 | show EUFargatevCPUHoursperCPU = "EU-Fargate-vCPU-Hours:perCPU" 48 | -------------------------------------------------------------------------------- /src/AWS/Lambda/Lambda.purs: -------------------------------------------------------------------------------- 1 | module AWS.Lambda 2 | ( Lambda 3 | , makeClient 4 | , invoke 5 | ) where 6 | 7 | import Prelude 8 | import AWS.Core.Client (makeClientHelper) 9 | import AWS.Core.Types (Arn(..), DefaultClientProps) 10 | import Control.Promise (Promise, toAffE) 11 | import Data.Argonaut (class EncodeJson, Json, encodeJson, stringify) 12 | import Data.Function.Uncurried (Fn2, runFn2) 13 | import Effect (Effect) 14 | import Effect.Aff (Aff) 15 | import Justifill (justifillVia) 16 | import Justifill.Fillable (class Fillable) 17 | import Justifill.Justifiable (class Justifiable) 18 | import Type.Proxy (Proxy(..)) 19 | 20 | type InternalLambdaParams 21 | = { "FunctionName" :: String 22 | , "Payload" :: String 23 | } 24 | 25 | foreign import data Lambda :: Type 26 | 27 | foreign import newLambda :: Json -> (Effect Lambda) 28 | 29 | makeClient :: 30 | forall r via. 31 | Justifiable { | r } { | via } => 32 | Fillable { | via } DefaultClientProps => 33 | { | r } -> 34 | Effect Lambda 35 | makeClient r = makeClientHelper newLambda props 36 | where 37 | viaProxy :: Proxy { | via } 38 | viaProxy = Proxy 39 | 40 | props :: DefaultClientProps 41 | props = justifillVia viaProxy r 42 | 43 | foreign import invokeImpl :: forall output. Fn2 Lambda InternalLambdaParams (Effect (Promise output)) 44 | 45 | invoke :: forall input output. EncodeJson input => Lambda -> Arn -> input -> Aff output 46 | invoke client (Arn arn) input = runFn2 invokeImpl client params # toAffE 47 | where 48 | params = 49 | { "FunctionName": arn 50 | , "Payload": stringify (encodeJson input) 51 | } 52 | -------------------------------------------------------------------------------- /src/AWS/EC2/Types.purs: -------------------------------------------------------------------------------- 1 | module AWS.EC2.Types where 2 | 3 | import Prelude (class Show) 4 | 5 | data Attribute 6 | = InstanceType 7 | | Kernel 8 | | Ramdisk 9 | | UserData 10 | | DisableApiTermination 11 | | InstanceInitiatedShutdownBehavior 12 | | RootDeviceName 13 | | BlockDeviceMapping 14 | | ProductCodes 15 | | SourceDestCheck 16 | | GroupSet 17 | | EbsOptimized 18 | | SriovNetSupport 19 | | EnaSupport 20 | | EnclaveOptions 21 | 22 | instance showAttribute :: Show Attribute where 23 | show InstanceType = "instanceType" 24 | show Kernel = "kernel" 25 | show Ramdisk = "ramdisk" 26 | show UserData = "userData" 27 | show DisableApiTermination = "disableApiTermination" 28 | show InstanceInitiatedShutdownBehavior = "instanceInitiatedShutdownBehavior" 29 | show RootDeviceName = "rootDeviceName" 30 | show BlockDeviceMapping = "blockDeviceMapping" 31 | show ProductCodes = "productCodes" 32 | show SourceDestCheck = "sourceDestCheck" 33 | show GroupSet = "groupSet" 34 | show EbsOptimized = "ebsOptimized" 35 | show SriovNetSupport = "sriovNetSupport" 36 | show EnaSupport = "enaSupport" 37 | show EnclaveOptions = "enclaveOptions" 38 | 39 | type InstanceAttributeInstanceType 40 | = { "InstanceId" :: String 41 | , "InstanceType" :: 42 | { "Value" :: String 43 | } 44 | } 45 | 46 | type VcpuInfo 47 | = { "DefaultVCpus" :: Int 48 | , "DefaultCores" :: Int 49 | , "DefaultThreadsPerCore" :: Int 50 | } 51 | 52 | type InstanceTypeParams 53 | = { "InstanceType" :: String 54 | , "VCpuInfo" :: VcpuInfo 55 | , "MemoryInfo" :: 56 | { "SizeInMiB" :: Int 57 | } 58 | } 59 | 60 | type DescribeInstanceTypesResponse 61 | = { "InstanceTypes" :: Array InstanceTypeParams 62 | } 63 | -------------------------------------------------------------------------------- /src/AWS/Pricing/ECS/Utils.purs: -------------------------------------------------------------------------------- 1 | module AWS.Pricing.ECS.Utils where 2 | 3 | import Prelude 4 | import AWS.Core.Types (Region) 5 | import AWS.Core.Util (handleError) 6 | import AWS.Pricing.ECS.Types (ECSAttributes, ECSPriceList, ECSProduct, ECSUsageType(..)) 7 | import AWS.Pricing.Types (FilterValue(..), InternalPriceList, InternalProduct) 8 | import AWS.Pricing.Utils (toTerms) 9 | import Data.Argonaut (Json, decodeJson) 10 | import Data.Bifunctor (lmap, bimap) 11 | import Data.Either (Either) 12 | import Data.Newtype (unwrap) 13 | 14 | toECSPriceList :: InternalPriceList -> ECSPriceList 15 | toECSPriceList pl = 16 | { serviceCode: pl.serviceCode 17 | , version: pl.version 18 | , publicationDate: pl.publicationDate 19 | , product: toECSProduct pl.product 20 | , terms: toTerms pl.terms 21 | } 22 | 23 | toECSProduct :: InternalProduct -> ECSProduct () 24 | toECSProduct internalProduct = 25 | { attributes: parseAttributes internalProduct.attributes 26 | } 27 | where 28 | parseAttributes :: Json -> Either String (ECSAttributes ()) 29 | parseAttributes = decodeJson <#> lmap handleError 30 | 31 | parseECSPriceList :: Json -> Either String ECSPriceList 32 | parseECSPriceList = decodeJson <#> bimap handleError toECSPriceList 33 | 34 | toFargateGBHours :: Region -> FilterValue 35 | toFargateGBHours region = case unwrap region of 36 | "eu-central-1" -> FilterValue $ show EUC1FargateGBHours 37 | "eu-west-1" -> FilterValue $ show EUFargateGBHours 38 | _ -> FilterValue $ "Unkown region" -- default value or error case? 39 | 40 | toFargatevCPUHours :: Region -> FilterValue 41 | toFargatevCPUHours region = case unwrap region of 42 | "eu-central-1" -> FilterValue $ show EUC1FargatevCPUHoursperCPU 43 | "eu-west-1" -> FilterValue $ show EUFargatevCPUHoursperCPU 44 | _ -> FilterValue $ "Unkown region" -- default value or error case? 45 | -------------------------------------------------------------------------------- /src/AWS/CostExplorer/Types.purs: -------------------------------------------------------------------------------- 1 | module AWS.CostExplorer.Types where 2 | 3 | import Prelude (class Show) 4 | import Data.Newtype (class Newtype) 5 | import Data.Maybe (Maybe) 6 | import Data.DateTime (DateTime) 7 | import Data.Argonaut.Encode (class EncodeJson) 8 | import Data.Argonaut.Decode (class DecodeJson) 9 | 10 | newtype NextPageToken 11 | = NextPageToken String 12 | 13 | derive instance ntNextPageToken :: Newtype NextPageToken _ 14 | 15 | derive newtype instance showNextPageToken :: Show NextPageToken 16 | 17 | derive newtype instance encodeNextPageToken :: EncodeJson NextPageToken 18 | 19 | derive newtype instance decodeNextPageToken :: DecodeJson NextPageToken 20 | 21 | newtype Key 22 | = Key String 23 | 24 | derive instance ntKey :: Newtype Key _ 25 | 26 | derive newtype instance showKey :: Show Key 27 | 28 | derive newtype instance encodeKey :: EncodeJson Key 29 | 30 | derive newtype instance decodeKey :: DecodeJson Key 31 | 32 | newtype Amount 33 | = Amount String 34 | 35 | derive instance ntAmount :: Newtype Amount _ 36 | 37 | derive newtype instance showAmount :: Show Amount 38 | 39 | derive newtype instance encodeAmount :: EncodeJson Amount 40 | 41 | derive newtype instance decodeAmount :: DecodeJson Amount 42 | 43 | type GroupDefinition 44 | = { key :: Maybe Key } 45 | 46 | type DateInterval 47 | = { start :: DateTime, end :: DateTime } 48 | 49 | type MetricValue 50 | = { amount :: Maybe Amount } 51 | 52 | type Metric 53 | = { unblendedCost :: Maybe MetricValue } 54 | 55 | type Group 56 | = { keys :: Array Key, metrics :: Maybe Metric } 57 | 58 | type ResultByTime 59 | = { timePeriod :: Maybe DateInterval, groups :: Array Group } 60 | 61 | type CostAndUsage 62 | = { resultsByTime :: Array ResultByTime 63 | , groupDefinitions :: Array GroupDefinition 64 | , nextPageToken :: Maybe NextPageToken 65 | } 66 | -------------------------------------------------------------------------------- /src/AWS/CloudWatch/Types.purs: -------------------------------------------------------------------------------- 1 | module AWS.CloudWatch.Types where 2 | 3 | import Data.Newtype (class Newtype) 4 | import Prelude (class Show) 5 | 6 | data Statistic 7 | = Minimum 8 | | Maximum 9 | | Average 10 | | SampleCount 11 | | Sum 12 | 13 | instance showStatistic :: Show Statistic where 14 | show Minimum = "Minimum" 15 | show Maximum = "Maximum" 16 | show Average = "Average" 17 | show SampleCount = "SampleCount" 18 | show Sum = "Sum" 19 | 20 | type Statistics 21 | = Array Statistic 22 | 23 | newtype DimensionValue 24 | = DimensionValue String 25 | 26 | derive instance ntDimensionValue :: Newtype DimensionValue _ 27 | 28 | derive newtype instance showDimensionValue :: Show DimensionValue 29 | 30 | data NameSpace 31 | = EC2 32 | | ECS 33 | 34 | instance showNameSpace :: Show NameSpace where 35 | show EC2 = "AWS/EC2" 36 | show ECS = "AWS/ECS" 37 | 38 | data DimensionName 39 | = EC2InstanceId 40 | | ClusterName 41 | 42 | instance showDimensionName :: Show DimensionName where 43 | show EC2InstanceId = "InstanceId" 44 | show ClusterName = "ClusterName" 45 | 46 | data MetricName 47 | = CPUUtilization 48 | | CPUReservation 49 | | MemoryUtilization 50 | | MemoryReservation 51 | 52 | instance showMetricName :: Show MetricName where 53 | show CPUUtilization = "CPUUtilization" 54 | show CPUReservation = "CPUReservation" 55 | show MemoryUtilization = "MemoryUtilization" 56 | show MemoryReservation = "MemoryReservation" 57 | 58 | type Dimension 59 | = { name :: DimensionName, value :: DimensionValue } 60 | 61 | type MetricSettings 62 | = { nameSpace :: NameSpace 63 | , metricName :: MetricName 64 | , dimensions :: Array Dimension 65 | } 66 | 67 | type Raw 68 | = ( "Timestamp" :: String, "Unit" :: String ) 69 | 70 | type MetricDatapointAverage 71 | = { "Average" :: Number | Raw } 72 | 73 | type MetricDatapointMaximum 74 | = { "Maximum" :: Number | Raw } 75 | 76 | type GetMetricStatisticsOutput a 77 | = { "ResponseMetadata" :: { "RequestId" :: String } 78 | , "Label" :: String 79 | , "Datapoints" :: Array a 80 | } 81 | -------------------------------------------------------------------------------- /src/AWS/Pricing/Utils.purs: -------------------------------------------------------------------------------- 1 | module AWS.Pricing.Utils where 2 | 3 | import Prelude 4 | import AWS.Core.Types (Region) 5 | import AWS.Pricing.Types (FilterValue(..), InternalOnDemand, InternalPriceDetails, InternalPriceDimension, InternalTerms, OnDemand(..), PriceDetails, PriceDimension, PriceDimensions(..), Terms, toUnit) 6 | import Data.DateTime (DateTime) 7 | import Data.Either (Either, hush) 8 | import Data.Formatter.DateTime (unformatDateTime) 9 | import Data.Newtype (unwrap) 10 | 11 | toTerms :: InternalTerms () -> Terms 12 | toTerms terms = { "OnDemand": toOnDemand terms."OnDemand" } 13 | 14 | toOnDemand :: InternalOnDemand -> OnDemand 15 | toOnDemand onDemand = (unwrap onDemand) <#> toPriceDetails # OnDemand 16 | 17 | toPriceDetails :: InternalPriceDetails () -> PriceDetails 18 | toPriceDetails priceDetails = 19 | { priceDimensions: 20 | (unwrap priceDetails.priceDimensions) 21 | <#> toPriceDimension 22 | # PriceDimensions 23 | , effectiveDate: hush $ parseDateTime priceDetails.effectiveDate 24 | } 25 | 26 | toPriceDimension :: InternalPriceDimension () -> PriceDimension 27 | toPriceDimension priceDimension = 28 | { description: priceDimension.description 29 | , unit: toUnit priceDimension.unit 30 | , pricePerUnit: priceDimension.pricePerUnit 31 | } 32 | 33 | parseDateTime :: String -> Either String DateTime 34 | parseDateTime = unformatDateTime "YYYY-MM-DDTHH:mm:ssZ" 35 | 36 | toLocation :: Region -> FilterValue 37 | toLocation r = case unwrap r of 38 | "eu-central-1" -> FilterValue "EU (Frankfurt)" 39 | "eu-west-1" -> FilterValue "EU (Ireland)" 40 | _ -> FilterValue "Unknown region" -- default value or error case? 41 | 42 | toBoxUsage :: Region -> String -> FilterValue 43 | toBoxUsage region instanceType = case unwrap region of 44 | "eu-central-1" -> FilterValue $ "EUC1-BoxUsage:" <> instanceType 45 | "eu-west-1" -> FilterValue $ "EU-BoxUsage:" <> instanceType 46 | _ -> FilterValue $ "Unkown region" -- default value or error case? 47 | 48 | {- 49 | Other possible values are: 50 | "EU-Reservation:" 51 | "EU-UnusedBox:" 52 | "EU-DedicatedRes:" 53 | "EU-BoxUsage:" 54 | "EU-UnusedDed:" 55 | "EU-DedicatedUsage:" 56 | "EU-HostBoxUsage:" 57 | -} 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # purescript-aws-sdk 2 | 3 | Purescript wrapper for AWS SDK. See [usage](#usage) 4 | 5 | ## tl;dr 6 | 7 | This is a Purescript wrapper for the AWS JavaScript SDK that we use for our projects at [Hivemind Technologies AG](https://hivemindtechnologies.com). Rather than aiming for a full compatibility of the AWS SDK, we strive for a wrapper that is Purescript-idomatic and covers the things that we need. If you are looking for a more complete but less idiomatic library, you might want to have a look into [purescript-aws-sdk](https://github.com/purescript-aws-sdk), which auto-generates Purescript code from the AWS SDK sources. 8 | 9 | Currently we have some functionality for the following modules: 10 | 11 | * CloudWatch 12 | * CloudWatchLogs 13 | * CostExplorer 14 | * EC2 15 | * Lambda 16 | * SecurityTokenService (STS) 17 | * DynamoDB 18 | * SecretsManager 19 | * KMS 20 | * S3 21 | 22 | While we do not have any plans to support other features that we currently don't use, we do welcome contributions of missing features. 23 | 24 | ## Installation 25 | 26 | ```bash 27 | spago install aws-sdk-basic 28 | ``` 29 | 30 | ## Usage 31 | 32 | ```purescript 33 | import Prelude 34 | import AWS.Lambda as AWSLambda 35 | import AWS.Core.Types 36 | import Effect.Aff (Aff) 37 | import Effect.Class (liftEffect) 38 | 39 | mydata = { name: "" } -- create some data 40 | 41 | type Result = { hello :: String } -- define some result type 42 | 43 | callLambda :: Aff Result 44 | callLambda = do 45 | client <- liftEffect $ AWSLambda.makeClient {} -- create the client 46 | let 47 | arn = Arn "arn:aws:lambda:<>:<>:function:<>" -- set the arn of your lambda 48 | result <- AWSLambda.invoke client arn mydata -- invoke the lambda 49 | pure result 50 | ``` 51 | 52 | The other modules work in a similar way. You create the client first, and then call a function passing the client as well as other parameters. 53 | 54 | You can customise the client by passing in any additonal options, e.g.: 55 | 56 | ```purescript 57 | EC2.makeClient 58 | { region: Region "eu-west-1" 59 | , accessKeyId : AccessKeyId "my-access-key-id" 60 | , secretAccessKey : AccessKeyId "my-secret-access-key" 61 | , sessionToken : SessionToken "my-session-token" 62 | } 63 | ``` 64 | -------------------------------------------------------------------------------- /src/AWS/SecretsManager/SecretsManager.purs: -------------------------------------------------------------------------------- 1 | module AWS.SecretsManager 2 | ( SecretsManager 3 | , makeClient 4 | , SecretId(..) 5 | , SecretString(..) 6 | , getSecretValue 7 | ) where 8 | 9 | import Prelude 10 | import AWS.Core.Client (makeClientHelper) 11 | import AWS.Core.Types (DefaultClientProps) 12 | import Control.Promise (Promise, toAffE) 13 | import Data.Argonaut (Json) 14 | import Data.Function.Uncurried (Fn2, runFn2) 15 | import Data.Newtype (class Newtype) 16 | import Effect (Effect) 17 | import Effect.Aff (Aff) 18 | import Justifill (justifillVia) 19 | import Justifill.Fillable (class Fillable) 20 | import Justifill.Justifiable (class Justifiable) 21 | import Type.Proxy (Proxy(..)) 22 | 23 | foreign import data SecretsManager :: Type 24 | 25 | foreign import newSecretsManager :: Json -> Effect SecretsManager 26 | 27 | makeClient :: 28 | forall r via. 29 | Justifiable { | r } { | via } => 30 | Fillable { | via } DefaultClientProps => 31 | { | r } -> 32 | Effect SecretsManager 33 | makeClient r = makeClientHelper newSecretsManager props 34 | where 35 | viaProxy :: Proxy { | via } 36 | viaProxy = Proxy 37 | 38 | props :: DefaultClientProps 39 | props = justifillVia viaProxy r 40 | 41 | type InternalGetSecretValueParams 42 | = { "SecretId" :: String 43 | } 44 | 45 | type InternalGetSecretValueResponse 46 | = { "Name" :: String 47 | , "SecretString" :: String 48 | } 49 | 50 | foreign import getSecretValueImpl :: Fn2 SecretsManager InternalGetSecretValueParams (Effect (Promise InternalGetSecretValueResponse)) 51 | 52 | newtype SecretId 53 | = SecretId String 54 | 55 | derive instance ntSecretId :: Newtype SecretId _ 56 | 57 | newtype SecretString 58 | = SecretString String 59 | 60 | derive instance ntSecretString :: Newtype SecretString _ 61 | 62 | type GetSecretValueResponse 63 | = { name :: SecretId 64 | , secretString :: SecretString 65 | } 66 | 67 | getSecretValue :: SecretsManager -> SecretId -> Aff GetSecretValueResponse 68 | getSecretValue client (SecretId name) = runFn2 getSecretValueImpl client params # toAffE <#> convert 69 | where 70 | params = { "SecretId": name } 71 | 72 | convert internalResponse = 73 | { name: SecretId internalResponse."Name" 74 | , secretString: SecretString internalResponse."SecretString" 75 | } 76 | -------------------------------------------------------------------------------- /src/AWS/ECS/Types.purs: -------------------------------------------------------------------------------- 1 | module AWS.ECS.Types where 2 | 3 | import Prelude (class Show) 4 | import Data.Newtype (class Newtype) 5 | 6 | newtype ClusterArn 7 | = ClusterArn String 8 | 9 | derive instance ntClusterArn :: Newtype ClusterArn _ 10 | 11 | derive newtype instance showClusterArn :: Show ClusterArn 12 | 13 | type Clusters 14 | = Array ClusterArn 15 | 16 | type ListClustersResponse 17 | = { clusterArns :: Clusters } 18 | 19 | newtype TaskArn 20 | = TaskArn String 21 | 22 | derive instance ntTaskArn :: Newtype TaskArn _ 23 | 24 | derive newtype instance showTaskArn :: Show TaskArn 25 | 26 | type Tasks 27 | = Array TaskArn 28 | 29 | type ListTasksResponse 30 | = { taskArns :: Tasks } 31 | 32 | newtype ContainerInstanceArn 33 | = ContainerInstanceArn String 34 | 35 | derive instance ntContainerInstanceArn :: Newtype ContainerInstanceArn _ 36 | 37 | derive newtype instance showContainerInstanceArn :: Show ContainerInstanceArn 38 | 39 | type ContainerInstances 40 | = Array ContainerInstanceArn 41 | 42 | type ListContainerInstancesResponse 43 | = { containerInstanceArns :: ContainerInstances } 44 | 45 | type ClusterParams 46 | = { clusterArn :: String 47 | , clusterName :: String 48 | , status :: String 49 | , registeredContainerInstancesCount :: Number 50 | } 51 | 52 | type DescribeClustersResponse 53 | = { clusters :: Array ClusterParams } 54 | 55 | type ContainerInstanceParams 56 | = { containerInstanceArn :: String 57 | , ec2InstanceId :: String 58 | } 59 | 60 | type DescribeContainerInstancesResponse 61 | = { containerInstances :: Array ContainerInstanceParams } 62 | 63 | {- 64 | { 65 | tasks: [ 66 | { 67 | attachments: [], 68 | availabilityZone: 'eu-central-1b', 69 | clusterArn: 'arn:aws:ecs:eu-central-1:foo/bar', 70 | connectivity: 'CONNECTED', 71 | connectivityAt: 2021-01-18T16:43:32.008Z, 72 | containerInstanceArn: 'arn:aws:ecs:eu-central-1:foo', 73 | containers: [Array], 74 | cpu: '512', 75 | createdAt: 2021-01-18T16:43:32.008Z, 76 | desiredStatus: 'RUNNING', 77 | enableExecuteCommand: false, 78 | group: 'my:group', 79 | healthStatus: 'UNKNOWN', 80 | lastStatus: 'RUNNING', 81 | launchType: 'EC2', 82 | memory: '512', 83 | overrides: [Object], 84 | pullStartedAt: 2021-01-18T16:43:32.115Z, 85 | pullStoppedAt: 2021-01-18T16:44:01.115Z, 86 | startedAt: 2021-01-18T16:44:02.115Z, 87 | startedBy: 'ecs-svc/xxxx', 88 | tags: [], 89 | taskArn: 'arn:aws:ecs:eu-central-1:bar', 90 | taskDefinitionArn: 'arn:aws:ecs:eu-central-1:foo', 91 | version: 2 92 | } 93 | ], 94 | failures: [] 95 | } 96 | -} 97 | type TaskDetails r 98 | = { cpu :: String 99 | , memory :: String 100 | | r 101 | } 102 | 103 | type Failure 104 | = { arn :: String 105 | , reason :: String 106 | , detail :: String 107 | } 108 | 109 | type DescribeTasksResponse r 110 | = { tasks :: Array (TaskDetails r) 111 | , failures :: Array Failure 112 | } 113 | -------------------------------------------------------------------------------- /src/AWS/Core/Types.purs: -------------------------------------------------------------------------------- 1 | module AWS.Core.Types where 2 | 3 | import Data.Argonaut (class DecodeJson, Json, JsonDecodeError, decodeJson) 4 | import Data.Argonaut.Encode (class EncodeJson) 5 | import Data.Either (Either) 6 | import Data.Map as Map 7 | import Data.Maybe (Maybe) 8 | import Data.Newtype (class Newtype) 9 | import Foreign.Object as F 10 | import Prelude (class Show, bind, ($), pure, (>>>), map) 11 | 12 | newtype AccessKeyId 13 | = AccessKeyId String 14 | 15 | derive instance ntAccessKeyId :: Newtype AccessKeyId _ 16 | 17 | derive newtype instance encodeAccessKeyId :: EncodeJson AccessKeyId 18 | 19 | newtype Region 20 | = Region String 21 | 22 | derive instance ntRegion :: Newtype Region _ 23 | 24 | derive newtype instance encodeRegion :: EncodeJson Region 25 | 26 | newtype SecretAccessKey 27 | = SecretAccessKey String 28 | 29 | derive instance ntSecretAccessKey :: Newtype SecretAccessKey _ 30 | 31 | derive newtype instance encodeSecretAccessKey :: EncodeJson SecretAccessKey 32 | 33 | newtype SessionToken 34 | = SessionToken String 35 | 36 | derive instance ntSessionToken :: Newtype SessionToken _ 37 | 38 | derive newtype instance encodeSessionToken :: EncodeJson SessionToken 39 | 40 | newtype Arn 41 | = Arn String 42 | 43 | derive instance ntArn :: Newtype Arn _ 44 | 45 | newtype ExternalId 46 | = ExternalId String 47 | 48 | derive instance ntExternalId :: Newtype ExternalId _ 49 | 50 | type Instance 51 | = { id :: InstanceId, "type" :: InstanceType } 52 | 53 | newtype InstanceId 54 | = InstanceId String 55 | 56 | derive instance ntInstanceId :: Newtype InstanceId _ 57 | 58 | derive newtype instance showInstanceId :: Show InstanceId 59 | 60 | newtype InstanceType 61 | = InstanceType String 62 | 63 | derive instance ntInstanceType :: Newtype InstanceType _ 64 | 65 | derive newtype instance showInstanceType :: Show InstanceType 66 | 67 | type Credentials 68 | = { accessKeyId :: Maybe AccessKeyId 69 | , secretAccessKey :: Maybe SecretAccessKey 70 | , sessionToken :: Maybe SessionToken 71 | } 72 | 73 | newtype Endpoint 74 | = Endpoint String 75 | 76 | derive instance ntEndpoint :: Newtype Endpoint _ 77 | 78 | derive newtype instance showEndpoint :: Show Endpoint 79 | 80 | derive newtype instance encodeEndpoint :: EncodeJson Endpoint 81 | 82 | decodeAsMap :: forall r. DecodeJson r => Json -> Either JsonDecodeError (Map.Map String r) 83 | decodeAsMap str = do 84 | obj <- decodeJson str 85 | pure $ Map.fromFoldable $ (F.toUnfoldable obj :: Array _) 86 | 87 | newtype Tags 88 | = Tags (Map.Map String String) 89 | 90 | derive newtype instance showTags :: Show Tags 91 | 92 | derive instance ntTags :: Newtype Tags _ 93 | 94 | instance tagsDecoder :: DecodeJson Tags where 95 | decodeJson = decodeAsMap >>> map Tags 96 | 97 | type BasicClientPropsR r 98 | = ( accessKeyId :: Maybe AccessKeyId 99 | , secretAccessKey :: Maybe SecretAccessKey 100 | , region :: Maybe Region 101 | , endpoint :: Maybe Endpoint 102 | , sessionToken :: Maybe SessionToken 103 | , credentials :: Maybe Credentials 104 | | r 105 | ) 106 | 107 | type BasicClientProps r 108 | = Record (BasicClientPropsR r) 109 | 110 | type DefaultClientPropsR 111 | = BasicClientPropsR () 112 | 113 | type DefaultClientProps 114 | = Record DefaultClientPropsR 115 | -------------------------------------------------------------------------------- /src/AWS/DynamoDB/DynamoDb.purs: -------------------------------------------------------------------------------- 1 | module AWS.DynamoDb 2 | ( DynamoDbClient 3 | , makeClient 4 | , putItem 5 | , GetItemOutput 6 | , getItem 7 | ) where 8 | 9 | import Prelude 10 | import AWS.Core.Client (makeClientHelper) 11 | import AWS.Core.Types (DefaultClientProps) 12 | import AWS.Core.Util (catchAwsError) 13 | import Control.Promise (Promise) 14 | import Control.Promise as Promise 15 | import Data.Argonaut (Json) 16 | import Data.Either (Either(..)) 17 | import Data.Function.Uncurried (Fn2, runFn2) 18 | import Data.Maybe (Maybe(..)) 19 | import Data.Nullable (Nullable) 20 | import Data.Nullable as Nullable 21 | import Effect (Effect) 22 | import Effect.Aff (Aff, Error, catchError) 23 | import Effect.Class (liftEffect) 24 | import Justifill (justifillVia) 25 | import Justifill.Fillable (class Fillable) 26 | import Justifill.Justifiable (class Justifiable) 27 | import Type.Proxy (Proxy(..)) 28 | 29 | foreign import data DynamoDbClient :: Type 30 | 31 | foreign import newDynamoDbClient :: Json -> (Effect DynamoDbClient) 32 | 33 | makeClient :: 34 | forall r via. 35 | Justifiable { | r } { | via } => 36 | Fillable { | via } DefaultClientProps => 37 | { | r } -> 38 | Effect DynamoDbClient 39 | makeClient r = makeClientHelper newDynamoDbClient props 40 | where 41 | viaProxy :: Proxy { | via } 42 | viaProxy = Proxy 43 | 44 | props :: DefaultClientProps 45 | props = justifillVia viaProxy r 46 | 47 | type GetItemInput input key 48 | = { "TableName" :: String, "Key" :: Record key | input } 49 | 50 | type PutItemInput input item 51 | = { "TableName" :: String, "Item" :: Record item | input } 52 | 53 | type InternalGetItemOutput output 54 | = { "Item" :: Nullable output } 55 | 56 | type GetItemOutput output 57 | = { item :: Maybe output } 58 | 59 | foreign import getItemImpl :: forall input key output. Fn2 DynamoDbClient (GetItemInput input key) (Effect (Promise (InternalGetItemOutput output))) 60 | 61 | getItem :: forall input key output. DynamoDbClient -> (GetItemInput input key) -> Aff (Either Error (GetItemOutput output)) 62 | getItem client input = liftEffect (curried client input) >>= Promise.toAff <#> toExternal # catchAwsError 63 | where 64 | toExternal response = 65 | { item: Nullable.toMaybe response."Item" } 66 | # Right 67 | 68 | curried = runFn2 getItemImpl 69 | 70 | foreign import putItemImpl :: forall input item. Fn2 DynamoDbClient (PutItemInput input item) (Effect (Promise Unit)) 71 | 72 | putItem :: forall input item. DynamoDbClient -> (PutItemInput input item) -> Aff (Maybe Error) 73 | putItem client input = liftEffect (curried client input) >>= Promise.toAff <#> toExternal # (flip catchError) (Just >>> pure) 74 | where 75 | toExternal response = Nothing 76 | 77 | curried = runFn2 putItemImpl 78 | 79 | type KeySchemaElement 80 | = { "AttributeName" :: String 81 | , "KeyType" :: String 82 | } 83 | 84 | type AttributeDefinition 85 | = { "AttributeName" :: String 86 | , "AttributeType" :: String 87 | } 88 | 89 | type CreateTableInput input 90 | = { "AttributeDefinitions" :: Array AttributeDefinition 91 | , "TableName" :: String 92 | , "KeySchema" :: Array KeySchemaElement 93 | | input 94 | } 95 | 96 | foreign import createTableImpl :: forall input. Fn2 DynamoDbClient (CreateTableInput input) (Effect (Promise Unit)) 97 | 98 | createTable :: forall input. DynamoDbClient -> (CreateTableInput input) -> Aff (Maybe Error) 99 | createTable client input = liftEffect (curried client input) >>= Promise.toAff <#> toExternal # (flip catchError) (Just >>> pure) 100 | where 101 | toExternal response = Nothing 102 | 103 | curried = runFn2 createTableImpl 104 | -------------------------------------------------------------------------------- /src/AWS/Pricing/Types.purs: -------------------------------------------------------------------------------- 1 | module AWS.Pricing.Types where 2 | 3 | import Prelude 4 | import AWS.Core.Types (decodeAsMap) 5 | import Data.Argonaut (class DecodeJson, Json) 6 | import Data.Argonaut.Encode (class EncodeJson) 7 | import Data.Argonaut.Encode.Encoders (encodeString) 8 | import Data.DateTime (DateTime) 9 | import Data.Map as Map 10 | import Data.Maybe (Maybe) 11 | import Data.Newtype (class Newtype) 12 | 13 | data FilterType 14 | = TERM_MATCH 15 | 16 | instance showFilterType :: Show FilterType where 17 | show TERM_MATCH = "TERM_MATCH" 18 | 19 | newtype FilterField 20 | = FilterField String 21 | 22 | derive instance ntFilterField :: Newtype FilterField _ 23 | 24 | newtype FilterValue 25 | = FilterValue String 26 | 27 | derive instance ntFilterValue :: Newtype FilterValue _ 28 | 29 | type Filter 30 | = { field :: FilterField 31 | , type :: FilterType 32 | , value :: FilterValue 33 | } 34 | 35 | data ServiceCode 36 | = AmazonEC2 37 | | AmazonECS 38 | 39 | instance showServiceCode :: Show ServiceCode where 40 | show AmazonEC2 = "AmazonEC2" 41 | show AmazonECS = "AmazonECS" 42 | 43 | type InternalProduct 44 | = { attributes :: Json } 45 | 46 | type InternalPriceDimension r 47 | = { description :: String 48 | , unit :: String 49 | , pricePerUnit :: { "USD" :: String } 50 | | r 51 | } 52 | 53 | newtype InternalPriceDimensions 54 | = InternalPriceDimensions (Map.Map String (InternalPriceDimension ())) 55 | 56 | derive newtype instance showPriceDimensions :: Show InternalPriceDimensions 57 | 58 | derive instance ntPriceDimensions :: Newtype InternalPriceDimensions _ 59 | 60 | instance priceDimensionsDecoder :: DecodeJson InternalPriceDimensions where 61 | decodeJson = decodeAsMap >>> map InternalPriceDimensions 62 | 63 | newtype InternalOnDemand 64 | = InternalOnDemand (Map.Map String (InternalPriceDetails ())) 65 | 66 | derive newtype instance showOnDemand :: Show InternalOnDemand 67 | 68 | derive instance ntOnDemand :: Newtype InternalOnDemand _ 69 | 70 | instance onDemandDecoder :: DecodeJson InternalOnDemand where 71 | decodeJson = decodeAsMap >>> map InternalOnDemand 72 | 73 | type InternalPriceDetails r 74 | = { priceDimensions :: InternalPriceDimensions 75 | , effectiveDate :: String 76 | | r 77 | } 78 | 79 | -- there is also "Reserved" prices 80 | -- but at the time of writing we don't need that information 81 | -- type InternalTerms r 82 | type InternalTerms r 83 | = { "OnDemand" :: InternalOnDemand 84 | | r 85 | } 86 | 87 | type InternalPriceList 88 | = { serviceCode :: String 89 | , version :: String 90 | , publicationDate :: String 91 | , product :: InternalProduct 92 | , terms :: InternalTerms () 93 | } 94 | 95 | type Terms 96 | = { "OnDemand" :: OnDemand } 97 | 98 | newtype OnDemand 99 | = OnDemand (Map.Map String PriceDetails) 100 | 101 | derive newtype instance showOnDemandA :: Show OnDemand 102 | 103 | derive instance ntOnDemandA :: Newtype OnDemand _ 104 | 105 | type PriceDetails 106 | = { priceDimensions :: PriceDimensions 107 | , effectiveDate :: Maybe DateTime 108 | } 109 | 110 | newtype PriceDimensions 111 | = PriceDimensions (Map.Map String PriceDimension) 112 | 113 | derive newtype instance showPriceDimensionsA :: Show PriceDimensions 114 | 115 | derive instance ntPriceDimensionsA :: Newtype PriceDimensions _ 116 | 117 | type PriceDimension 118 | = { description :: String 119 | , unit :: PriceUnit 120 | , pricePerUnit :: { "USD" :: String } 121 | } 122 | 123 | data PriceUnit 124 | = Hours 125 | | Quantity 126 | 127 | instance encodeUnit :: EncodeJson PriceUnit where 128 | encodeJson Hours = encodeString "Hrs" 129 | encodeJson Quantity = encodeString "Quantity" 130 | 131 | instance showUnit :: Show PriceUnit where 132 | show Hours = "Hrs" 133 | show Quantity = "Quantity" 134 | 135 | derive instance eqUnit :: Eq PriceUnit 136 | 137 | toUnit :: String -> PriceUnit 138 | toUnit unit = case unit of 139 | "Hrs" -> Hours 140 | "Quantity" -> Quantity 141 | _ -> Hours 142 | -------------------------------------------------------------------------------- /src/AWS/CloudWatch/Cloudwatch.purs: -------------------------------------------------------------------------------- 1 | module AWS.CloudWatch 2 | ( CloudWatch 3 | , makeClient 4 | , getMetricStatisticsAverage 5 | , getMetricStatisticsMaximum 6 | ) where 7 | 8 | import Prelude 9 | import AWS.CloudWatch.Types (Dimension, GetMetricStatisticsOutput, MetricDatapointMaximum, MetricSettings, Statistics, MetricDatapointAverage) 10 | import AWS.Core.Client (makeClientHelper) 11 | import AWS.Core.Types (DefaultClientProps) 12 | import AWS.Core.Util (handleError) 13 | import Control.Promise (Promise) 14 | import Control.Promise as Promise 15 | import Data.Argonaut (Json, parseJson) 16 | import Data.Argonaut.Decode (decodeJson) 17 | import Data.Bifunctor (lmap) 18 | import Data.DateTime (DateTime) 19 | import Data.Either (Either) 20 | import Data.Function.Uncurried (Fn2, runFn2) 21 | import Data.JSDate (JSDate, fromDateTime) 22 | import Data.Newtype (unwrap) 23 | import Effect (Effect) 24 | import Effect.Aff (Aff) 25 | import Effect.Class (liftEffect) 26 | import Justifill (justifillVia) 27 | import Justifill.Fillable (class Fillable) 28 | import Justifill.Justifiable (class Justifiable) 29 | import Type.Proxy (Proxy(..)) 30 | 31 | foreign import data CloudWatch :: Type 32 | 33 | foreign import newCloudWatch :: Json -> (Effect CloudWatch) 34 | 35 | makeClient :: 36 | forall r via. 37 | Justifiable { | r } { | via } => 38 | Fillable { | via } DefaultClientProps => 39 | { | r } -> 40 | Effect CloudWatch 41 | makeClient r = makeClientHelper newCloudWatch props 42 | where 43 | viaProxy :: Proxy { | via } 44 | viaProxy = Proxy 45 | 46 | props :: DefaultClientProps 47 | props = justifillVia viaProxy r 48 | 49 | type InternalGetMetricsStatisticsParams 50 | = { "Dimensions" :: Array { "Name" :: String, "Value" :: String } 51 | , "MetricName" :: String 52 | , "Namespace" :: String 53 | , "Period" :: Int 54 | , "StartTime" :: JSDate 55 | , "EndTime" :: JSDate 56 | , "Statistics" :: Array String 57 | } 58 | 59 | type InternalDimension 60 | = { "Name" :: String, "Value" :: String } 61 | 62 | toInternalDimension :: Dimension -> InternalDimension 63 | toInternalDimension dimension = 64 | { "Name": show dimension.name 65 | , "Value": unwrap dimension.value 66 | } 67 | 68 | toInternalGetMetricStatisticsParams :: 69 | forall a. 70 | { start :: DateTime, end :: DateTime | a } -> 71 | Statistics -> 72 | MetricSettings -> 73 | InternalGetMetricsStatisticsParams 74 | toInternalGetMetricStatisticsParams range statistics ms = 75 | { "Namespace": nameSpace 76 | , "MetricName": metricName 77 | , "Dimensions": dimensions 78 | , "Statistics": stat 79 | , "StartTime": start 80 | , "EndTime": end 81 | , "Period": 3600 -- per hour 82 | } 83 | where 84 | nameSpace = show ms.nameSpace 85 | 86 | metricName = show ms.metricName 87 | 88 | dimensions = ms.dimensions <#> toInternalDimension 89 | 90 | stat = statistics <#> show 91 | 92 | start = fromDateTime range.start 93 | 94 | end = fromDateTime range.end 95 | 96 | foreign import getMetricStatisticsImpl :: Fn2 CloudWatch InternalGetMetricsStatisticsParams (Effect (Promise String)) 97 | 98 | curried :: 99 | forall a. 100 | CloudWatch -> 101 | { start :: DateTime, end :: DateTime | a } -> 102 | Statistics -> 103 | MetricSettings -> 104 | Effect (Promise String) 105 | curried cw range statistics ms = runFn2 getMetricStatisticsImpl cw params 106 | where 107 | params :: InternalGetMetricsStatisticsParams 108 | params = toInternalGetMetricStatisticsParams range statistics ms 109 | 110 | getMetricStatisticsMaximum :: 111 | forall a. 112 | CloudWatch -> 113 | { start :: DateTime, end :: DateTime | a } -> 114 | Statistics -> 115 | MetricSettings -> 116 | Aff (Either String (GetMetricStatisticsOutput MetricDatapointMaximum)) 117 | getMetricStatisticsMaximum cw range statistics ms = liftEffect (curried cw range statistics ms) >>= Promise.toAff <#> parse 118 | where 119 | parse :: String -> Either String (GetMetricStatisticsOutput MetricDatapointMaximum) 120 | parse = (parseJson >=> decodeJson) >>> lmap handleError 121 | 122 | getMetricStatisticsAverage :: 123 | forall a. 124 | CloudWatch -> 125 | { start :: DateTime, end :: DateTime | a } -> 126 | Statistics -> 127 | MetricSettings -> 128 | Aff (Either String (GetMetricStatisticsOutput MetricDatapointAverage)) 129 | getMetricStatisticsAverage cw range statistics ms = liftEffect (curried cw range statistics ms) >>= Promise.toAff <#> parse 130 | where 131 | parse :: String -> Either String (GetMetricStatisticsOutput MetricDatapointAverage) 132 | parse = (parseJson >=> decodeJson) >>> lmap handleError 133 | -------------------------------------------------------------------------------- /src/AWS/KMS/KMS.purs: -------------------------------------------------------------------------------- 1 | module AWS.KMS 2 | ( makeClient 3 | , KMS 4 | , EncryptionParams 5 | , Algorithm(..) 6 | , Ciphertext 7 | , Plaintext 8 | , EncryptionInput 9 | , EncryptionOutput 10 | , DecryptionInput 11 | , DecryptionOutput 12 | , decrypt 13 | , encrypt 14 | ) where 15 | 16 | import Prelude 17 | import AWS.Core.Client (makeClientHelper) 18 | import AWS.Core.Types (Arn(..), DefaultClientProps) 19 | import AWS.Core.Util (raiseEither) 20 | import Control.Promise (Promise, toAffE) 21 | import Data.Argonaut (Json) 22 | import Data.Either (Either(..)) 23 | import Data.Function.Uncurried (Fn2, runFn2) 24 | import Data.Newtype (un) 25 | import Effect (Effect) 26 | import Effect.Aff (Aff) 27 | import Justifill (justifillVia) 28 | import Justifill.Fillable (class Fillable) 29 | import Justifill.Justifiable (class Justifiable) 30 | import Type.Proxy (Proxy(..)) 31 | 32 | foreign import data KMS :: Type 33 | 34 | foreign import newKMS :: Json -> Effect KMS 35 | 36 | makeClient :: 37 | forall r via. 38 | Justifiable { | r } { | via } => 39 | Fillable { | via } DefaultClientProps => 40 | { | r } -> 41 | Effect KMS 42 | makeClient r = makeClientHelper newKMS props 43 | where 44 | viaProxy :: Proxy { | via } 45 | viaProxy = Proxy 46 | 47 | props :: DefaultClientProps 48 | props = justifillVia viaProxy r 49 | 50 | type InternalEncryptionParams r 51 | = ( "KeyId" :: String 52 | , "EncryptionAlgorithm" :: String 53 | | r 54 | ) 55 | 56 | type InternalPlaintext r 57 | = ( "Plaintext" :: String | r ) 58 | 59 | type InternalCiphertext r 60 | = ( "CiphertextBlob" :: String | r ) 61 | 62 | type InternalEncryptionInput 63 | = Record (InternalEncryptionParams (InternalPlaintext ())) 64 | 65 | type InternalEncryptionOutput 66 | = Record (InternalEncryptionParams (InternalCiphertext ())) 67 | 68 | data Algorithm 69 | = SYMMETRIC_DEFAULT 70 | | RSAES_OAEP_SHA_1 71 | | RSAES_OAEP_SHA_256 72 | 73 | toInternal :: Algorithm -> String 74 | toInternal SYMMETRIC_DEFAULT = "SYMMETRIC_DEFAULT" 75 | 76 | toInternal RSAES_OAEP_SHA_1 = "RSAES_OAEP_SHA_1" 77 | 78 | toInternal RSAES_OAEP_SHA_256 = "RSAES_OAEP_SHA_256" 79 | 80 | fromInternal :: String -> Either String Algorithm 81 | fromInternal "SYMMETRIC_DEFAULT" = Right SYMMETRIC_DEFAULT 82 | 83 | fromInternal "RSAES_OAEP_SHA_1" = Right RSAES_OAEP_SHA_1 84 | 85 | fromInternal "RSAES_OAEP_SHA_256" = Right RSAES_OAEP_SHA_256 86 | 87 | fromInternal alg = Left $ "Unable to parse algorithm " <> alg 88 | 89 | type EncryptionParams r 90 | = ( keyId :: Arn 91 | , algorithm :: Algorithm 92 | | r 93 | ) 94 | 95 | type Ciphertext r 96 | = ( ciphertext :: String | r ) 97 | 98 | type Plaintext r 99 | = ( plaintext :: String | r ) 100 | 101 | type EncryptionInput 102 | = Record (EncryptionParams (Plaintext ())) 103 | 104 | type EncryptionOutput 105 | = Record (EncryptionParams (Ciphertext ())) 106 | 107 | foreign import encryptImpl :: Fn2 KMS InternalEncryptionInput (Effect (Promise InternalEncryptionOutput)) 108 | 109 | encrypt :: KMS -> EncryptionInput -> Aff EncryptionOutput 110 | encrypt client input = runFn2 encryptImpl client params # toAffE <#> convert >>= raiseEither 111 | where 112 | params = 113 | { "KeyId": un Arn input.keyId 114 | , "EncryptionAlgorithm": toInternal input.algorithm 115 | , "Plaintext": input.plaintext 116 | } 117 | 118 | convert :: InternalEncryptionOutput -> Either String EncryptionOutput 119 | convert internal = 120 | fromInternal internal."EncryptionAlgorithm" 121 | <#> \alg -> { keyId: Arn internal."KeyId", algorithm: alg, ciphertext: internal."CiphertextBlob" } 122 | 123 | type InternalDecryptionInput 124 | = Record (InternalEncryptionParams (InternalCiphertext ())) 125 | 126 | type InternalDecryptionOutput 127 | = Record (InternalEncryptionParams (InternalPlaintext ())) 128 | 129 | type DecryptionInput 130 | = Record (EncryptionParams (Ciphertext ())) 131 | 132 | type DecryptionOutput 133 | = Record (EncryptionParams (Plaintext ())) 134 | 135 | foreign import decryptImpl :: Fn2 KMS InternalDecryptionInput (Effect (Promise InternalDecryptionOutput)) 136 | 137 | decrypt :: KMS -> DecryptionInput -> Aff DecryptionOutput 138 | decrypt client input = runFn2 decryptImpl client params # toAffE <#> convert >>= raiseEither 139 | where 140 | params = 141 | { "KeyId": un Arn input.keyId 142 | , "EncryptionAlgorithm": toInternal input.algorithm 143 | , "CiphertextBlob": input.ciphertext 144 | } 145 | 146 | convert :: InternalDecryptionOutput -> Either String DecryptionOutput 147 | convert internal = 148 | fromInternal internal."EncryptionAlgorithm" 149 | <#> \alg -> { keyId: Arn internal."KeyId", algorithm: alg, plaintext: internal."Plaintext" } 150 | -------------------------------------------------------------------------------- /src/AWS/SecurityTokenService/SecurityTokenService.purs: -------------------------------------------------------------------------------- 1 | module AWS.SecurityTokenService (STS, StsRegionalEndpoint(..), RoleSessionName(..), STSProps, STSPropsR, makeClient, makeRegionalClient, assumeRole) where 2 | 3 | import Prelude 4 | import AWS.Core.Client (makeClientHelper) 5 | import AWS.Core.Types (AccessKeyId(..), Arn(..), BasicClientPropsR, ExternalId(..), SecretAccessKey(..), SessionToken(..), DefaultClientProps) 6 | import Control.Promise (Promise) 7 | import Control.Promise as Promise 8 | import Data.Argonaut (Json) 9 | import Data.Argonaut.Encode (class EncodeJson) 10 | import Data.Argonaut.Encode.Encoders (encodeString) 11 | import Data.Function.Uncurried (Fn2, runFn2) 12 | import Data.Int (round) 13 | import Data.Maybe (Maybe(..)) 14 | import Data.Newtype (un, class Newtype) 15 | import Data.Nullable (Nullable, toMaybe) 16 | import Data.Nullable as Nullable 17 | import Data.Time.Duration (Seconds(..)) 18 | import Effect (Effect) 19 | import Effect.Aff (Aff) 20 | import Effect.Class (liftEffect) 21 | import Effect.Exception (throw) 22 | import Justifill (justifill, justifillVia) 23 | import Justifill.Fillable (class Fillable) 24 | import Justifill.Justifiable (class Justifiable, class JustifiableFields) 25 | import Prim.Row (class Nub, class Union) 26 | import Prim.RowList (class RowToList) 27 | import Record (merge) 28 | import Type.Proxy (Proxy(..)) 29 | 30 | foreign import data STS :: Type 31 | 32 | foreign import newSTS :: Json -> Effect STS 33 | 34 | data StsRegionalEndpoint 35 | = Regional 36 | | Legacy 37 | 38 | instance encodeStsRegionalEndpoint :: EncodeJson StsRegionalEndpoint where 39 | encodeJson Regional = encodeString "regional" 40 | encodeJson Legacy = encodeString "legacy" 41 | 42 | newtype RoleSessionName 43 | = RoleSessionName String 44 | 45 | derive instance ntRoleSessionName :: Newtype RoleSessionName _ 46 | 47 | type STSPropsR 48 | = BasicClientPropsR ( stsRegionalEndpoint :: Maybe StsRegionalEndpoint ) 49 | 50 | type STSProps 51 | = Record STSPropsR 52 | 53 | makeClient :: 54 | forall r via. 55 | Justifiable { | r } { | via } => 56 | Fillable { | via } STSProps => 57 | { | r } -> 58 | Effect STS 59 | makeClient r = makeClientHelper newSTS props 60 | where 61 | viaProxy :: Proxy { | via } 62 | viaProxy = Proxy 63 | 64 | props :: STSProps 65 | props = justifillVia viaProxy r 66 | 67 | -- | Make a sts client that uses regional sts service endpoints instead of the global (legacy) 68 | makeRegionalClient :: 69 | forall r rSts rStsNubbed rStsNubbedL via. 70 | Union r ( stsRegionalEndpoint :: Maybe StsRegionalEndpoint ) rSts => 71 | Nub rSts rStsNubbed => 72 | RowToList rStsNubbed rStsNubbedL => 73 | JustifiableFields rStsNubbedL rStsNubbed () via => 74 | Fillable { | via } STSProps => 75 | { | r } -> 76 | Effect STS 77 | makeRegionalClient props = merge props { stsRegionalEndpoint: Just Regional } # makeClient 78 | 79 | type InternalAssumeRoleParams 80 | = { "RoleArn" :: String 81 | , "ExternalId" :: Nullable String 82 | , "RoleSessionName" :: String 83 | , "DurationSeconds" :: Nullable Int 84 | } 85 | 86 | type InternalAssumeRoleResponse 87 | = { "Credentials" :: Nullable InternalCredentials 88 | , "AssumedRoleUser" :: Nullable InternalAssumedRoleUser 89 | } 90 | 91 | type InternalCredentials 92 | = { "AccessKeyId" :: String 93 | , "SecretAccessKey" :: String 94 | , "SessionToken" :: String 95 | } 96 | 97 | type InternalAssumedRoleUser 98 | = { "AssumedRoleId" :: String 99 | , "Arn" :: String 100 | } 101 | 102 | foreign import assumeRoleImpl :: Fn2 STS InternalAssumeRoleParams (Effect (Promise InternalAssumeRoleResponse)) 103 | 104 | assumeRole :: STS -> Arn -> Maybe ExternalId -> RoleSessionName -> Maybe Seconds -> Aff DefaultClientProps 105 | assumeRole sts roleArn externalId roleSessionName seconds = toExternal =<< Promise.toAffE curried 106 | where 107 | toCredentials :: InternalAssumeRoleResponse -> Maybe DefaultClientProps 108 | toCredentials r = 109 | toMaybe r."Credentials" 110 | <#> \creds -> 111 | justifill 112 | { accessKeyId: (AccessKeyId creds."AccessKeyId") 113 | , secretAccessKey: (SecretAccessKey creds."SecretAccessKey") 114 | , sessionToken: (SessionToken creds."SessionToken") 115 | } 116 | 117 | toExternal :: InternalAssumeRoleResponse -> Aff DefaultClientProps 118 | toExternal i = 119 | liftEffect case toCredentials i of 120 | Just credentials -> pure credentials 121 | Nothing -> throw "Failed to assume role" 122 | 123 | extractSeconds :: Seconds -> Int 124 | extractSeconds (Seconds s) = round s 125 | 126 | params :: InternalAssumeRoleParams 127 | params = 128 | { "RoleArn": un Arn roleArn 129 | , "ExternalId": Nullable.toNullable $ externalId <#> un ExternalId 130 | , "RoleSessionName": un RoleSessionName roleSessionName 131 | , "DurationSeconds": Nullable.toNullable (seconds <#> extractSeconds) 132 | } 133 | 134 | curried = runFn2 assumeRoleImpl sts params 135 | -------------------------------------------------------------------------------- /src/AWS/Pricing/Pricing.purs: -------------------------------------------------------------------------------- 1 | module AWS.Pricing 2 | ( Pricing 3 | , makeClient 4 | , getEC2Products 5 | , getECSProducts 6 | , getAllEC2Products 7 | ) where 8 | 9 | import Prelude 10 | import AWS.Core.Client (makeClientHelper) 11 | import AWS.Core.Types (DefaultClientProps) 12 | import AWS.Core.Util (unfoldrM1) 13 | import AWS.Pricing.EC2.Types (GetEC2ProductsResponse, EC2PriceList) 14 | import AWS.Pricing.EC2.Utils (parseEC2PriceList) 15 | import AWS.Pricing.ECS.Types (GetECSProductsResponse) 16 | import AWS.Pricing.ECS.Utils (parseECSPriceList) 17 | import AWS.Pricing.Types (Filter, ServiceCode) 18 | import AWS.Pricing.Types as ServiceCode 19 | import Control.Promise (Promise, toAffE) 20 | import Data.Argonaut (Json) 21 | import Data.Either (Either) 22 | import Data.Function.Uncurried (Fn5, runFn5) 23 | import Data.Maybe (Maybe(..)) 24 | import Data.Newtype (unwrap) 25 | import Data.Nullable (Nullable) 26 | import Data.Nullable as Nullable 27 | import Data.Tuple (Tuple(..)) 28 | import Effect (Effect) 29 | import Effect.Aff (Aff) 30 | import Justifill (justifillVia) 31 | import Justifill.Fillable (class Fillable) 32 | import Justifill.Justifiable (class Justifiable) 33 | import Type.Proxy (Proxy(..)) 34 | 35 | foreign import data Pricing :: Type 36 | 37 | foreign import newPricing :: Json -> Effect Pricing 38 | 39 | makeClient :: 40 | forall r via. 41 | Justifiable { | r } { | via } => 42 | Fillable { | via } DefaultClientProps => 43 | { | r } -> 44 | Effect Pricing 45 | makeClient r = makeClientHelper newPricing props 46 | where 47 | viaProxy :: Proxy { | via } 48 | viaProxy = Proxy 49 | 50 | props :: DefaultClientProps 51 | props = justifillVia viaProxy r 52 | 53 | type InternalFilter 54 | = { "Field" :: String 55 | , "Type" :: String 56 | , "Value" :: String 57 | } 58 | 59 | type InternalGetProductsResponse 60 | = { "FormatVersion" :: String 61 | , "PriceList" :: Array Json 62 | , "NextToken" :: Nullable String 63 | } 64 | 65 | foreign import getProductsImpl :: 66 | Fn5 67 | Pricing 68 | (Array InternalFilter) 69 | String 70 | (Nullable String) 71 | (Nullable Number) 72 | (Effect (Promise InternalGetProductsResponse)) 73 | 74 | curried :: 75 | Pricing -> 76 | Array Filter -> 77 | ServiceCode -> 78 | Maybe String -> 79 | Maybe Number -> 80 | Aff InternalGetProductsResponse 81 | curried pricing filters serviceCode token max = 82 | ( toAffE 83 | $ runFn5 getProductsImpl 84 | pricing 85 | (filters <#> toInternalFilter) 86 | (show serviceCode) 87 | (Nullable.toNullable token) 88 | (Nullable.toNullable max) 89 | ) 90 | where 91 | toInternalFilter :: Filter -> InternalFilter 92 | toInternalFilter filter = 93 | { "Field": unwrap filter.field 94 | , "Type": show filter.type 95 | , "Value": unwrap filter.value 96 | } 97 | 98 | getEC2Products :: 99 | Pricing -> 100 | Array Filter -> 101 | Maybe String -> 102 | Maybe Number -> 103 | Aff GetEC2ProductsResponse 104 | getEC2Products pricing filters token max = curried pricing filters ServiceCode.AmazonEC2 token max <#> toResponse 105 | where 106 | toResponse :: InternalGetProductsResponse -> GetEC2ProductsResponse 107 | toResponse internal = 108 | { formatVersion: internal."FormatVersion" 109 | , priceList: internal."PriceList" <#> parseEC2PriceList 110 | , nextToken: Nullable.toMaybe internal."NextToken" 111 | } 112 | 113 | getECSProducts :: 114 | Pricing -> 115 | Array Filter -> 116 | Maybe String -> 117 | Maybe Number -> 118 | Aff GetECSProductsResponse 119 | getECSProducts pricing filters token max = curried pricing filters ServiceCode.AmazonECS token max <#> toResponse 120 | where 121 | toResponse :: InternalGetProductsResponse -> GetECSProductsResponse 122 | toResponse internal = 123 | { formatVersion: internal."FormatVersion" 124 | , priceList: internal."PriceList" <#> parseECSPriceList 125 | , nextToken: Nullable.toMaybe internal."NextToken" 126 | } 127 | 128 | getAllEC2Products :: 129 | Pricing -> 130 | Array Filter -> 131 | Aff (Array (Either String EC2PriceList)) 132 | getAllEC2Products api filters = do 133 | initial :: GetEC2ProductsResponse <- getEC2Products api filters Nothing Nothing 134 | next :: Array (Array (Either String EC2PriceList)) <- fetchAllNext initial.nextToken 135 | let 136 | all :: Array (Array (Either String EC2PriceList)) 137 | all = pure initial.priceList <> next 138 | 139 | allFlatten :: Array (Either String EC2PriceList) 140 | allFlatten = all # join 141 | pure allFlatten 142 | where 143 | -- func 144 | getProductsAndNextToken :: 145 | String -> 146 | Aff 147 | ( Tuple 148 | (Array (Either String EC2PriceList)) 149 | (Maybe String) 150 | ) 151 | getProductsAndNextToken currentNextToken = do 152 | products <- getEC2Products api filters (Just currentNextToken) Nothing 153 | let 154 | nextToken = products.nextToken 155 | 156 | priceList = products.priceList 157 | pure $ Tuple priceList nextToken 158 | 159 | fetchAllNext :: Maybe String -> Aff (Array (Array (Either String EC2PriceList))) 160 | fetchAllNext token = unfoldrM1 token getProductsAndNextToken 161 | -------------------------------------------------------------------------------- /src/AWS/CostExplorer/CostExplorer.purs: -------------------------------------------------------------------------------- 1 | module AWS.CostExplorer 2 | ( CE 3 | , makeClient 4 | , getCostAndUsage 5 | ) where 6 | 7 | import Prelude 8 | import AWS.Core.Client (makeClientHelper) 9 | import AWS.Core.Types (DefaultClientProps) 10 | import AWS.Core.Util (raiseEither, toIso8601Date, joinNullArr) 11 | import AWS.CostExplorer.Types (CostAndUsage, DateInterval, Group, GroupDefinition, MetricValue, NextPageToken(..), ResultByTime, Key(..), Amount(..), Metric) 12 | import Control.Promise (Promise) 13 | import Control.Promise as Promise 14 | import Data.Argonaut (Json) 15 | import Data.DateTime (DateTime) 16 | import Data.Either (hush, Either) 17 | import Data.Formatter.DateTime (unformatDateTime) 18 | import Data.Function.Uncurried (Fn2, runFn2) 19 | import Data.Maybe (Maybe) 20 | import Data.Nullable (Nullable, toMaybe, null) 21 | import Effect (Effect) 22 | import Effect.Aff (Aff) 23 | import Justifill (justifillVia) 24 | import Justifill.Fillable (class Fillable) 25 | import Justifill.Justifiable (class Justifiable) 26 | import Type.Proxy (Proxy(..)) 27 | 28 | foreign import data CE :: Type 29 | 30 | foreign import newCE :: Json -> (Effect CE) 31 | 32 | makeClient :: 33 | forall r via. 34 | Justifiable { | r } { | via } => 35 | Fillable { | via } DefaultClientProps => 36 | { | r } -> 37 | Effect CE 38 | makeClient r = makeClientHelper newCE props 39 | where 40 | viaProxy :: Proxy { | via } 41 | viaProxy = Proxy 42 | 43 | props :: DefaultClientProps 44 | props = justifillVia viaProxy r 45 | 46 | -- https://github.com/aws/aws-sdk-js/blob/dabf8b11e6e0d61d4dc2ab62717b8735fb8b29e4/clients/costexplorer.d.ts#L649 47 | type InternalGetCostAndUsageResponse 48 | = { "ResultsByTime" :: Nullable (Array InternalResultByTime) 49 | , "GroupDefinitions" :: Nullable (Array InternalGroupDefinition) 50 | , "NextPageToken" :: Nullable (String) 51 | } 52 | 53 | toCostAndUsage :: InternalGetCostAndUsageResponse -> CostAndUsage 54 | toCostAndUsage internal = 55 | { resultsByTime: joinNullArr internal."ResultsByTime" <#> toResultByTime 56 | , groupDefinitions: joinNullArr internal."GroupDefinitions" <#> toGroupDefinition 57 | , nextPageToken: toMaybe internal."NextPageToken" <#> NextPageToken 58 | } 59 | 60 | type InternalGroupDefinition 61 | = { "Key" :: Nullable String } 62 | 63 | toGroupDefinition :: InternalGroupDefinition -> GroupDefinition 64 | toGroupDefinition internal = { key: toMaybe internal."Key" <#> Key } 65 | 66 | type InternalResultByTime 67 | = { "TimePeriod" :: Nullable InternalDateInterval, "Groups" :: Nullable (Array InternalGroup) } 68 | 69 | toResultByTime :: InternalResultByTime -> ResultByTime 70 | toResultByTime internal = 71 | { timePeriod: toMaybe internal."TimePeriod" >>= toDateInterval 72 | , groups: joinNullArr internal."Groups" <#> toGroup 73 | } 74 | 75 | type InternalDateInterval 76 | = { "Start" :: String, "End" :: String } 77 | 78 | parseDateTime :: String -> Either String DateTime 79 | parseDateTime = unformatDateTime "YYYY-MM-DD" 80 | 81 | toDateInterval :: InternalDateInterval -> Maybe DateInterval 82 | toDateInterval internal = 83 | hush 84 | $ do 85 | start <- parseDateTime internal."Start" 86 | end <- parseDateTime internal."End" 87 | pure { start, end } 88 | 89 | type InternalGroup 90 | = { "Keys" :: Nullable (Array String), "Metrics" :: Nullable InternalMetric } 91 | 92 | toGroup :: InternalGroup -> Group 93 | toGroup internal = 94 | { keys: joinNullArr internal."Keys" <#> Key 95 | , metrics: toMaybe internal."Metrics" <#> toMetric 96 | } 97 | 98 | type InternalMetric 99 | = { "UnblendedCost" :: Nullable InternalMetricValue } 100 | 101 | toMetric :: InternalMetric -> Metric 102 | toMetric internal = { unblendedCost: toMaybe internal."UnblendedCost" <#> toMetricValue } 103 | 104 | type InternalMetricValue 105 | = { "Amount" :: Nullable String } 106 | 107 | toMetricValue :: InternalMetricValue -> MetricValue 108 | toMetricValue internal = { amount: toMaybe internal."Amount" <#> Amount } 109 | 110 | foreign import getCostAndUsageImpl :: Fn2 CE InternalGetCostAndUsageParams (Effect (Promise InternalGetCostAndUsageResponse)) 111 | 112 | -- https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CostExplorer.html#getCostAndUsage-property 113 | type InternalGetCostAndUsageParams 114 | = { "Granularity" :: String 115 | , "GroupBy" :: Array { "Key" :: String, "Type" :: String } 116 | , "Metrics" :: Array String 117 | , "TimePeriod" :: { "End" :: String, "Start" :: String } 118 | , "NextPageToken" :: Nullable String 119 | } 120 | 121 | getCostAndUsage :: 122 | CE -> 123 | DateInterval -> 124 | Aff CostAndUsage 125 | getCostAndUsage ce range = do 126 | start <- raiseEither $ toIso8601Date range.start 127 | end <- raiseEither $ toIso8601Date range.end 128 | internalResp <- _getCostAndUsage ce start end null 129 | pure (toCostAndUsage internalResp) 130 | 131 | _getCostAndUsage :: 132 | CE -> 133 | String -> 134 | String -> 135 | Nullable String -> 136 | Aff InternalGetCostAndUsageResponse 137 | _getCostAndUsage ce start end nextPageToken = do 138 | result <- 139 | Promise.toAffE 140 | $ runFn2 getCostAndUsageImpl ce 141 | { "TimePeriod": 142 | { "Start": start 143 | , "End": end 144 | } 145 | , "Granularity": "DAILY" 146 | , "GroupBy": 147 | [ { "Key": "SERVICE" 148 | , "Type": "DIMENSION" 149 | } 150 | , { "Key": "USAGE_TYPE" 151 | , "Type": "DIMENSION" 152 | } 153 | ] 154 | , "Metrics": [ "UnblendedCost" ] 155 | , "NextPageToken": nextPageToken 156 | } 157 | pure result 158 | -------------------------------------------------------------------------------- /src/AWS/S3/S3.purs: -------------------------------------------------------------------------------- 1 | module AWS.S3 2 | ( S3 3 | , BucketKey(..) 4 | , BucketName(..) 5 | , BucketPolicyParams 6 | , BucketPolicy(..) 7 | , createBucket 8 | , CreateBucketResponse 9 | , getObject 10 | , GetObjectParams 11 | , GetObjectResponse 12 | , makeClient 13 | , putBucketPolicy 14 | , GetSignedUrlParams 15 | , Operation(..) 16 | , SignedUrl(..) 17 | , getSignedUrl 18 | ) where 19 | 20 | import AWS.Core.Client (makeClientHelper) 21 | import AWS.Core.Types (DefaultClientProps, Region(..), Tags) 22 | import AWS.Core.Util (raiseEither) 23 | import Control.Bind ((>>=)) 24 | import Control.Promise (Promise, toAffE) 25 | import Data.Argonaut (Json, JsonDecodeError, decodeJson) 26 | import Data.Bifunctor (lmap) 27 | import Data.Either (Either) 28 | import Data.Function.Uncurried (Fn2, runFn2, Fn3, runFn3) 29 | import Data.Int (round) 30 | import Data.Newtype (class Newtype) 31 | import Data.Show (show) 32 | import Data.Time.Duration (Seconds(..)) 33 | import Effect (Effect) 34 | import Effect.Aff (Aff) 35 | import Justifill (justifillVia) 36 | import Justifill.Fillable (class Fillable) 37 | import Justifill.Justifiable (class Justifiable) 38 | import Node.Buffer (Buffer) 39 | import Prelude (class Show, Unit, (#), ($), (<#>), (>>>)) 40 | import Type.Proxy (Proxy(..)) 41 | 42 | foreign import data S3 :: Type 43 | 44 | foreign import newS3 :: Json -> Effect S3 45 | 46 | makeClient :: 47 | forall r via. 48 | Justifiable { | r } { | via } => 49 | Fillable { | via } DefaultClientProps => 50 | { | r } -> 51 | Effect S3 52 | makeClient r = makeClientHelper newS3 props 53 | where 54 | viaProxy :: Proxy { | via } 55 | viaProxy = Proxy 56 | 57 | props :: DefaultClientProps 58 | props = justifillVia viaProxy r 59 | 60 | newtype BucketName 61 | = BucketName String 62 | 63 | derive instance ntBucketName :: Newtype BucketName _ 64 | 65 | derive newtype instance showBucketName :: Show BucketName 66 | 67 | type InternalGetObjectParams 68 | = { "Bucket" :: String 69 | , "Key" :: String 70 | } 71 | 72 | type InternalGetObjectResponse 73 | = { "Body" :: Buffer 74 | , "ContentLength" :: Int 75 | , "ContentEncoding" :: String 76 | , "ContentType" :: String 77 | , "Metadata" :: Json 78 | } 79 | 80 | foreign import getObjectImpl :: Fn2 S3 InternalGetObjectParams (Effect (Promise InternalGetObjectResponse)) 81 | 82 | newtype BucketKey 83 | = BucketKey String 84 | 85 | derive instance ntBucketKey :: Newtype BucketKey _ 86 | 87 | type GetObjectParams 88 | = { bucket :: BucketName 89 | , key :: BucketKey 90 | } 91 | 92 | type GetObjectResponse 93 | = { body :: Buffer 94 | , contentLength :: Int 95 | , contentEncoding :: String 96 | , contentType :: String 97 | , tags :: Tags 98 | } 99 | 100 | getObject :: S3 -> GetObjectParams -> Aff GetObjectResponse 101 | getObject client { bucket: BucketName name, key: BucketKey key } = 102 | runFn2 getObjectImpl client params 103 | # toAffE 104 | >>= (convert >>> lmap show >>> raiseEither) 105 | where 106 | params = 107 | { "Bucket": name 108 | , "Key": key 109 | } 110 | 111 | convert :: InternalGetObjectResponse -> Either JsonDecodeError GetObjectResponse 112 | convert internalResponse = parse internalResponse."Metadata" <#> addTags 113 | where 114 | addTags tags = 115 | { body: internalResponse."Body" 116 | , contentLength: internalResponse."ContentLength" 117 | , contentEncoding: internalResponse."ContentEncoding" 118 | , contentType: internalResponse."ContentType" 119 | , tags: tags 120 | } 121 | 122 | parse :: Json -> Either JsonDecodeError Tags 123 | parse = decodeJson 124 | 125 | type InternalGetSignedUrlParams 126 | = { "Bucket" :: String 127 | , "Key" :: String 128 | , "Expires" :: Int 129 | } 130 | 131 | type GetSignedUrlParams 132 | = { bucket :: BucketName 133 | , key :: BucketKey 134 | , expires :: Seconds 135 | } 136 | 137 | data Operation 138 | = GetObject 139 | | PutObject 140 | 141 | newtype SignedUrl 142 | = SignedUrl String 143 | 144 | derive instance ntSignedUrl :: Newtype SignedUrl _ 145 | 146 | derive newtype instance showSignedUrl :: Show SignedUrl 147 | 148 | foreign import getSignedUrlImpl :: Fn3 S3 String InternalGetSignedUrlParams (Effect (Promise String)) 149 | 150 | getSignedUrl :: S3 -> Operation -> GetSignedUrlParams -> Aff SignedUrl 151 | getSignedUrl s3 operation { bucket: BucketName bucketName, key: BucketKey bucketKey, expires: Seconds seconds } = runFn3 getSignedUrlImpl s3 (toString operation) params # toAffE <#> SignedUrl 152 | where 153 | toString GetObject = "getObject" 154 | 155 | toString PutObject = "putObject" 156 | 157 | params = { "Bucket": bucketName, "Key": bucketKey, "Expires": round seconds } 158 | 159 | foreign import createBucketImpl :: Fn3 S3 String InternalBucketConfiguration (Effect (Promise InternalCreateBucketResponse)) 160 | 161 | type InternalBucketConfiguration 162 | = { "LocationConstraint" :: String } 163 | 164 | type InternalCreateBucketResponse 165 | = { "Location" :: String } 166 | 167 | type CreateBucketResponse 168 | = { location :: Region } 169 | 170 | createBucket :: S3 -> BucketName -> Region -> Aff CreateBucketResponse 171 | createBucket s3 (BucketName name) (Region region) = 172 | runFn3 createBucketImpl s3 name bucketConfig 173 | # toAffE 174 | <#> convert 175 | where 176 | bucketConfig :: InternalBucketConfiguration 177 | bucketConfig = { "LocationConstraint": region } 178 | 179 | convert :: InternalCreateBucketResponse -> CreateBucketResponse 180 | convert internalResponse = { location: Region internalResponse."Location" } 181 | 182 | foreign import putBucketPolicyImpl :: Fn3 S3 String String (Effect (Promise Unit)) 183 | 184 | type BucketPolicyParams 185 | = { name :: BucketName 186 | , policy :: BucketPolicy 187 | } 188 | 189 | newtype BucketPolicy 190 | = BucketPolicy String 191 | 192 | derive instance ntBucketPolicy :: Newtype BucketPolicy _ 193 | 194 | derive newtype instance showBucketPolicy :: Show BucketPolicy 195 | 196 | putBucketPolicy :: S3 -> BucketName -> BucketPolicy -> Aff Unit 197 | putBucketPolicy s3 (BucketName name) (BucketPolicy policy) = 198 | toAffE 199 | $ runFn3 putBucketPolicyImpl s3 name policy 200 | -------------------------------------------------------------------------------- /src/AWS/ECS/ECS.purs: -------------------------------------------------------------------------------- 1 | module AWS.ECS 2 | ( ECS 3 | , makeClient 4 | , listClusters 5 | , listTasks 6 | , listContainerInstances 7 | , describeClusters 8 | , describeContainerInstances 9 | , newECS 10 | , describeTasks 11 | ) where 12 | 13 | import Prelude 14 | import AWS.Core.Client (makeClientHelper) 15 | import AWS.Core.Types (DefaultClientProps) 16 | import AWS.Core.Util (handleError) 17 | import AWS.ECS.Types (Tasks, DescribeTasksResponse, ClusterArn(..), ClusterParams, Clusters, ContainerInstanceArn(..), ContainerInstanceParams, ContainerInstances, DescribeClustersResponse, DescribeContainerInstancesResponse, ListClustersResponse, ListTasksResponse, ListContainerInstancesResponse) 18 | import Control.Promise (Promise, toAffE) 19 | import Data.Argonaut (Json, decodeJson) 20 | import Data.Bifunctor (lmap) 21 | import Data.Either (Either) 22 | import Data.Function.Uncurried (Fn1, Fn2, Fn3, runFn1, runFn2, runFn3) 23 | import Data.Newtype (un, wrap, unwrap) 24 | import Effect (Effect) 25 | import Effect.Aff (Aff) 26 | import Justifill (justifillVia) 27 | import Justifill.Fillable (class Fillable) 28 | import Justifill.Justifiable (class Justifiable) 29 | import Type.Proxy (Proxy(..)) 30 | 31 | foreign import data ECS :: Type 32 | 33 | foreign import newECS :: Json -> (Effect ECS) 34 | 35 | makeClient :: 36 | forall r via. 37 | Justifiable { | r } { | via } => 38 | Fillable { | via } DefaultClientProps => 39 | { | r } -> 40 | Effect ECS 41 | makeClient r = makeClientHelper newECS props 42 | where 43 | viaProxy :: Proxy { | via } 44 | viaProxy = Proxy 45 | 46 | props :: DefaultClientProps 47 | props = justifillVia viaProxy r 48 | 49 | type InternalListClustersResponse 50 | = { clusterArns :: Array String } 51 | 52 | foreign import listClustersImpl :: Fn1 ECS (Effect (Promise InternalListClustersResponse)) 53 | 54 | listClusters :: ECS -> Aff ListClustersResponse 55 | listClusters ecs = 56 | runFn1 listClustersImpl ecs 57 | # toAffE 58 | <#> toResponse 59 | where 60 | toResponse :: InternalListClustersResponse -> ListClustersResponse 61 | toResponse internalRspse = { clusterArns: internalRspse."clusterArns" <#> wrap } 62 | 63 | foreign import listTasksImpl :: Fn3 ECS String String (Effect (Promise InternalListTasksResponse)) 64 | 65 | type InternalListTasksResponse 66 | = { taskArns :: Array String } 67 | 68 | listTasks :: ECS -> ClusterArn -> ContainerInstanceArn -> Aff ListTasksResponse 69 | listTasks ecs clusterArn containerInstanceArn = 70 | runFn3 listTasksImpl ecs (un ClusterArn clusterArn) (un ContainerInstanceArn containerInstanceArn) 71 | # toAffE 72 | <#> toResponse 73 | where 74 | toResponse :: InternalListTasksResponse -> ListTasksResponse 75 | toResponse internalRspse = { taskArns: internalRspse."taskArns" <#> wrap } 76 | 77 | foreign import listContainerInstancesImpl :: Fn2 ECS String (Effect (Promise InternalListContainerInstancesResponse)) 78 | 79 | type InternalListContainerInstancesResponse 80 | = { containerInstanceArns :: Array String } 81 | 82 | listContainerInstances :: ECS -> ClusterArn -> Aff ListContainerInstancesResponse 83 | listContainerInstances ecs clusterArn = 84 | runFn2 listContainerInstancesImpl ecs (un ClusterArn clusterArn) 85 | # toAffE 86 | <#> toResponse 87 | where 88 | toResponse :: InternalListContainerInstancesResponse -> ListContainerInstancesResponse 89 | toResponse internalRspse = { containerInstanceArns: internalRspse."containerInstanceArns" <#> wrap } 90 | 91 | type InternalCluster r 92 | = { clusterArn :: String 93 | , clusterName :: String 94 | , status :: String 95 | , registeredContainerInstancesCount :: Number 96 | | r 97 | } 98 | 99 | type InternalDescribeClustersResponse r 100 | = { clusters :: Array (InternalCluster r) } 101 | 102 | foreign import describeClustersImpl :: forall r. Fn2 ECS (Array String) (Effect (Promise (InternalDescribeClustersResponse r))) 103 | 104 | describeClusters :: ECS -> Clusters -> Aff DescribeClustersResponse 105 | describeClusters ecs clusterArns = 106 | runFn2 describeClustersImpl ecs (clusterArns <#> unwrap) 107 | # toAffE 108 | <#> toResponse 109 | where 110 | toResponse :: forall r. InternalDescribeClustersResponse r -> DescribeClustersResponse 111 | toResponse internalRspse = { clusters: internalRspse."clusters" <#> toClusterParams } 112 | 113 | toClusterParams :: forall r. InternalCluster r -> ClusterParams 114 | toClusterParams i = 115 | { clusterArn: i.clusterArn 116 | , clusterName: i.clusterName 117 | , status: i.status 118 | , registeredContainerInstancesCount: i.registeredContainerInstancesCount 119 | } 120 | 121 | type InternalContainerInstanceParams r 122 | = { containerInstanceArn :: String 123 | , ec2InstanceId :: String 124 | | r 125 | } 126 | 127 | type InternalDescribeContainerInstancesResponse r 128 | = { containerInstances :: Array (InternalContainerInstanceParams r) } 129 | 130 | foreign import describeContainerInstancesImpl :: forall r. Fn3 ECS String (Array String) (Effect (Promise (InternalDescribeContainerInstancesResponse r))) 131 | 132 | describeContainerInstances :: ECS -> ClusterArn -> ContainerInstances -> Aff DescribeContainerInstancesResponse 133 | describeContainerInstances ecs clusterArn containers = 134 | runFn3 describeContainerInstancesImpl ecs (unwrap clusterArn) (containers <#> unwrap) 135 | # toAffE 136 | <#> toResponse 137 | where 138 | toResponse :: forall r. InternalDescribeContainerInstancesResponse r -> DescribeContainerInstancesResponse 139 | toResponse internalRspse = { containerInstances: internalRspse."containerInstances" <#> toContainerInstanceParams } 140 | 141 | toContainerInstanceParams :: forall r. InternalContainerInstanceParams r -> ContainerInstanceParams 142 | toContainerInstanceParams i = 143 | { containerInstanceArn: i.containerInstanceArn 144 | , ec2InstanceId: i.ec2InstanceId 145 | } 146 | 147 | foreign import describeTasksImpl :: Fn3 ECS (Array String) String (Effect (Promise (Json))) 148 | 149 | describeTasks :: ECS -> Tasks -> ClusterArn -> Aff (Either String (DescribeTasksResponse ())) 150 | describeTasks ecs tasks cluster = 151 | runFn3 describeTasksImpl ecs (tasks <#> unwrap) (unwrap cluster) 152 | # toAffE 153 | <#> parse 154 | where 155 | parse :: Json -> Either String (DescribeTasksResponse ()) 156 | parse = decodeJson <#> lmap handleError 157 | -------------------------------------------------------------------------------- /src/AWS/EC2/EC2.purs: -------------------------------------------------------------------------------- 1 | module AWS.EC2 2 | ( EC2 3 | , makeClient 4 | , describeInstances 5 | , Filter(..) 6 | , ResourceTypeName(..) 7 | , describeTags 8 | , DescribeTagsResponse 9 | , Tag 10 | , describeInstanceAttributeInstanceType 11 | , newEC2 12 | , describeInstanceTypes 13 | , InstanceStateName(..) 14 | ) where 15 | 16 | import Prelude 17 | 18 | import AWS.Core.Client (makeClientHelper) 19 | import AWS.Core.Types (DefaultClientProps, Instance, InstanceId(..), InstanceType(..)) 20 | import AWS.Core.Util (handleError) 21 | import AWS.EC2.Types (Attribute(..)) as Attribute 22 | import AWS.EC2.Types (Attribute, InstanceAttributeInstanceType, DescribeInstanceTypesResponse) 23 | import Control.Promise (Promise, toAffE) 24 | import Data.Argonaut (Json, decodeJson) 25 | import Data.Bifunctor (lmap) 26 | import Data.Either (Either) 27 | import Data.Function.Uncurried (Fn2, Fn3, runFn2, runFn3) 28 | import Data.Newtype (unwrap) 29 | import Effect (Effect) 30 | import Effect.Aff (Aff) 31 | import Justifill (justifillVia) 32 | import Justifill.Fillable (class Fillable) 33 | import Justifill.Justifiable (class Justifiable) 34 | import Type.Proxy (Proxy(..)) 35 | 36 | foreign import data EC2 :: Type 37 | 38 | foreign import newEC2 :: Json -> (Effect EC2) 39 | 40 | makeClient :: 41 | forall r via. 42 | Justifiable { | r } { | via } => 43 | Fillable { | via } DefaultClientProps => 44 | { | r } -> 45 | Effect EC2 46 | makeClient r = makeClientHelper newEC2 props 47 | where 48 | viaProxy :: Proxy { | via } 49 | viaProxy = Proxy 50 | 51 | props :: DefaultClientProps 52 | props = justifillVia viaProxy r 53 | 54 | type InternalEC2Instance 55 | = { "InstanceId" :: String, "InstanceType" :: String } 56 | 57 | type InternalEC2Reservation 58 | = { "Instances" :: Array InternalEC2Instance } 59 | 60 | type InternalEC2Response 61 | = { "Reservations" :: Array InternalEC2Reservation } 62 | 63 | foreign import describeInstancesImpl :: Fn2 EC2 (Array InternalFilter) (Effect (Promise InternalEC2Response)) 64 | 65 | describeInstances :: EC2 -> Array Filter -> Aff (Array Instance) 66 | describeInstances ec2 filters = runFn2 describeInstancesImpl ec2 internalFilters # toAffE <#> toExternal 67 | where 68 | toExternal :: InternalEC2Response -> Array Instance 69 | toExternal response = do 70 | reservations <- response."Reservations" 71 | instances <- reservations."Instances" 72 | pure 73 | { id: InstanceId instances."InstanceId" 74 | , "type": InstanceType instances."InstanceType" 75 | } 76 | 77 | internalFilters :: Array InternalFilter 78 | internalFilters = filters <#> toInternalFilter 79 | 80 | data ResourceTypeName 81 | = CustomerGateway 82 | | DedicatedHost 83 | | DhcpOptions 84 | | ElasticIp 85 | | Fleet 86 | | FpgaImage 87 | | HostReservation 88 | | Image 89 | | Instance 90 | | InternetGateway 91 | | KeyPair 92 | | LaunchTemplate 93 | | Natgateway 94 | | NetworkAcl 95 | | NetworkInterface 96 | | PlacementGroup 97 | | ReservedInstances 98 | | RouteTable 99 | | SecurityGroup 100 | | Snapshot 101 | | SpotInstancesRequest 102 | | Subnet 103 | | Volume 104 | | Vpc 105 | | VpcEndpoint 106 | | VpcEndpointService 107 | | VpcPeeringConnection 108 | | VpnConnection 109 | | VpnGateway 110 | 111 | toInternalResourceTypeName :: ResourceTypeName -> String 112 | toInternalResourceTypeName resourceTypeName = case resourceTypeName of 113 | CustomerGateway -> "customer-gateway" 114 | DedicatedHost -> "dedicated-host" 115 | DhcpOptions -> "dhcp-options" 116 | ElasticIp -> "elastic-ip" 117 | Fleet -> "fleet" 118 | FpgaImage -> "fpga-image" 119 | HostReservation -> "host-reservation" 120 | Image -> "image" 121 | Instance -> "instance" 122 | InternetGateway -> "internet-gateway" 123 | KeyPair -> "key-pair" 124 | LaunchTemplate -> "launch-template" 125 | Natgateway -> "natgateway" 126 | NetworkAcl -> "network-acl" 127 | NetworkInterface -> "network-interface" 128 | PlacementGroup -> "placement-group" 129 | ReservedInstances -> "reserved-instances" 130 | RouteTable -> "route-table" 131 | SecurityGroup -> "security-group" 132 | Snapshot -> "snapshot" 133 | SpotInstancesRequest -> "spot-instances-request" 134 | Subnet -> "subnet" 135 | Volume -> "volume" 136 | Vpc -> "vpc" 137 | VpcEndpoint -> "vpc-endpoint" 138 | VpcEndpointService -> "vpc-endpoint-service" 139 | VpcPeeringConnection -> "vpc-peering-connection" 140 | VpnConnection -> "vpn-connection" 141 | VpnGateway -> "vpn-gateway" 142 | 143 | data InstanceStateName 144 | = Pending 145 | | Running 146 | | ShuttingDown 147 | | Terminated 148 | | Stopping 149 | | Stopped 150 | 151 | toInternalInstanceStateName :: InstanceStateName -> String 152 | toInternalInstanceStateName state = case state of 153 | Pending -> "pending" 154 | Running -> "running" 155 | ShuttingDown -> "shutting-down" 156 | Terminated -> "terminated" 157 | Stopping -> "stopping" 158 | Stopped -> "stopped" 159 | 160 | data Filter 161 | = Key (Array String) 162 | | ResourceId (Array String) 163 | | ResourceType (Array ResourceTypeName) 164 | | Tag String (Array String) 165 | | Value (Array String) 166 | | InstanceStateName (Array InstanceStateName) 167 | 168 | type InternalFilter 169 | = { "Name" :: String, "Values" :: Array String } 170 | 171 | toInternalFilter :: Filter -> InternalFilter 172 | toInternalFilter filter = case filter of 173 | Key values -> { "Name": "key", "Values": values } 174 | ResourceId values -> { "Name": "resource-id", "Values": values } 175 | ResourceType values -> { "Name": "resource-type", "Values": values <#> toInternalResourceTypeName } 176 | Tag key values -> { "Name": "tag:" <> key, "Values": values } 177 | Value values -> { "Name": "value:", "Values": values } 178 | InstanceStateName values -> { "Name": "instance-state-name", "Values": values <#> toInternalInstanceStateName } 179 | 180 | type InternalTag 181 | = { "ResourceType" :: String 182 | , "ResourceId" :: String 183 | , "Value" :: String 184 | , "Key" :: String 185 | } 186 | 187 | type InternalDescribeTagsResponse 188 | = { "Tags" :: Array InternalTag 189 | } 190 | 191 | type Tag 192 | = { resourceType :: String 193 | , resourceId :: String 194 | , value :: String 195 | , key :: String 196 | } 197 | 198 | type DescribeTagsResponse 199 | = { tags :: Array Tag 200 | } 201 | 202 | toTag :: InternalTag -> Tag 203 | toTag internalTag = 204 | { resourceType: internalTag."ResourceType" 205 | , resourceId: internalTag."ResourceId" 206 | , value: internalTag."Value" 207 | , key: internalTag."Key" 208 | } 209 | 210 | foreign import describeTagsImpl :: Fn2 EC2 (Array InternalFilter) (Effect (Promise InternalDescribeTagsResponse)) 211 | 212 | describeTags :: EC2 -> Array Filter -> Aff DescribeTagsResponse 213 | describeTags ec2 filters = 214 | runFn2 describeTagsImpl ec2 internalFilters 215 | # toAffE 216 | <#> toResponse 217 | where 218 | internalFilters :: Array InternalFilter 219 | internalFilters = filters <#> toInternalFilter 220 | 221 | toResponse :: InternalDescribeTagsResponse -> DescribeTagsResponse 222 | toResponse internalRspse = { tags: internalRspse."Tags" <#> toTag } 223 | 224 | foreign import describeInstanceAttributeImpl :: Fn3 EC2 String String (Effect (Promise Json)) 225 | 226 | curriedInstanceAttribute :: EC2 -> Attribute -> InstanceId -> Effect (Promise Json) 227 | curriedInstanceAttribute ec2 attribute instanceId = 228 | runFn3 describeInstanceAttributeImpl 229 | ec2 230 | (show attribute) 231 | (unwrap instanceId) 232 | 233 | describeInstanceAttributeInstanceType :: EC2 -> InstanceId -> Aff (Either String InstanceAttributeInstanceType) 234 | describeInstanceAttributeInstanceType ec2 instanceId = 235 | (toAffE $ curriedInstanceAttribute ec2 Attribute.InstanceType instanceId) 236 | <#> parse 237 | where 238 | parse :: Json -> Either String InstanceAttributeInstanceType 239 | parse = decodeJson <#> lmap handleError 240 | 241 | foreign import describeInstanceTypesImpl :: Fn2 EC2 (Array String) (Effect (Promise Json)) 242 | 243 | curriedInstanceTypes :: EC2 -> Array InstanceType -> Effect (Promise Json) 244 | curriedInstanceTypes ec2 instanceTypes = 245 | runFn2 describeInstanceTypesImpl 246 | ec2 247 | (instanceTypes <#> unwrap) 248 | 249 | describeInstanceTypes :: EC2 -> Array InstanceType -> Aff (Either String DescribeInstanceTypesResponse) 250 | describeInstanceTypes ec2 instanceTypes = 251 | (toAffE $ curriedInstanceTypes ec2 instanceTypes) 252 | <#> parse 253 | where 254 | parse :: Json -> Either String (DescribeInstanceTypesResponse) 255 | parse = decodeJson <#> lmap handleError 256 | -------------------------------------------------------------------------------- /src/AWS/Core/Util.purs: -------------------------------------------------------------------------------- 1 | module AWS.Core.Util where 2 | 3 | import Prelude 4 | import Control.Monad.Error.Class (class MonadError, class MonadThrow, catchError, throwError) 5 | import Data.Argonaut.Decode (JsonDecodeError) 6 | import Data.DateTime (DateTime) 7 | import Data.Either (Either(..), either) 8 | import Data.Formatter.DateTime (formatDateTime) 9 | import Data.Maybe (Maybe(..)) 10 | import Data.Nullable (Nullable, toMaybe) 11 | import Data.Tuple (Tuple, fst, snd) 12 | import Data.Unfoldable (fromMaybe) 13 | import Effect.Exception (Error, error) 14 | 15 | toIso8601Date :: DateTime -> Either String String 16 | toIso8601Date d = formatDateTime "YYYY-MM-DD" d 17 | 18 | raiseEither :: forall m r. MonadThrow Error m => Either String r -> m r 19 | raiseEither = either (error >>> throwError) pure 20 | 21 | joinNullArr :: forall a. Nullable (Array a) -> Array a 22 | joinNullArr = nullToArr >>> join 23 | 24 | nullToArr :: forall a. Nullable a -> Array a 25 | nullToArr = toMaybe >>> fromMaybe 26 | 27 | catchAwsError :: forall m e s. MonadError e m => m (Either e s) -> m (Either e s) 28 | catchAwsError = (flip catchError) (Left >>> pure) 29 | 30 | handleError :: JsonDecodeError -> String 31 | handleError = show 32 | 33 | -- | Unfolds a monadic value with the given function. 34 | -- | The generating function may put the result into the first element of the tuple 35 | -- | and at the second element the element which needs to be passed on (if there is any of course). 36 | -- | The first element of the result tuple will be accumlated with the other results and returned at the end. 37 | -- | and wrapped in `ls`. 38 | -- foldRecM :: forall m a b. MonadRec m => (b -> a -> m b) -> b -> Array a -> m b 39 | unfoldrM1 :: 40 | forall m ls a b. 41 | Monad m => 42 | Monoid (m a) => 43 | Applicative ls => 44 | Monoid (ls b) => 45 | Maybe a -> 46 | (a -> m (Tuple b (Maybe a))) -> 47 | m (ls b) 48 | unfoldrM1 initialMaybeToken func = do 49 | let 50 | rec (resSoFar :: ls b) maybeToken = do 51 | case maybeToken of 52 | Just newValue -> do 53 | res :: Tuple b (Maybe a) <- func newValue 54 | let 55 | newResSoFar :: ls b 56 | newResSoFar = resSoFar <> (pure $ fst res) 57 | rec newResSoFar $ snd res 58 | Nothing -> pure resSoFar 59 | rec mempty initialMaybeToken 60 | 61 | -- replace hard coded array with the describe-instance-type-offerings call 62 | -- aws ec2 describe-instance-type-offerings --query "InstanceTypeOfferings[].InstanceType" --region eu-west-1 63 | ec2InstanceTypes :: Array String 64 | ec2InstanceTypes = 65 | [ "t1.micro" 66 | , "t2.nano" 67 | , "t2.micro" 68 | , "t2.small" 69 | , "t2.medium" 70 | , "t2.large" 71 | , "t2.xlarge" 72 | , "t2.2xlarge" 73 | , "t3.nano" 74 | , "t3.micro" 75 | , "t3.small" 76 | , "t3.medium" 77 | , "t3.large" 78 | , "t3.xlarge" 79 | , "t3.2xlarge" 80 | , "t3a.nano" 81 | , "t3a.micro" 82 | , "t3a.small" 83 | , "t3a.medium" 84 | , "t3a.large" 85 | , "t3a.xlarge" 86 | , "t3a.2xlarge" 87 | , "t4g.nano" 88 | , "t4g.micro" 89 | , "t4g.small" 90 | , "t4g.medium" 91 | , "t4g.large" 92 | , "t4g.xlarge" 93 | , "t4g.2xlarge" 94 | , "m1.small" 95 | , "m1.medium" 96 | , "m1.large" 97 | , "m1.xlarge" 98 | , "m3.medium" 99 | , "m3.large" 100 | , "m3.xlarge" 101 | , "m3.2xlarge" 102 | , "m4.large" 103 | , "m4.xlarge" 104 | , "m4.2xlarge" 105 | , "m4.4xlarge" 106 | , "m4.10xlarge" 107 | , "m4.16xlarge" 108 | , "m2.xlarge" 109 | , "m2.2xlarge" 110 | , "m2.4xlarge" 111 | , "cr1.8xlarge" 112 | , "r3.large" 113 | , "r3.xlarge" 114 | , "r3.2xlarge" 115 | , "r3.4xlarge" 116 | , "r3.8xlarge" 117 | , "r4.large" 118 | , "r4.xlarge" 119 | , "r4.2xlarge" 120 | , "r4.4xlarge" 121 | , "r4.8xlarge" 122 | , "r4.16xlarge" 123 | , "r5.large" 124 | , "r5.xlarge" 125 | , "r5.2xlarge" 126 | , "r5.4xlarge" 127 | , "r5.8xarge" 128 | , "r5.12xlarge" 129 | , "r5.16xlarge" 130 | , "r5.24xlarge" 131 | , "r5.metal" 132 | , "r5a.large" 133 | , "r5a.xlarge" 134 | , "r5a.2xlarge" 135 | , "r5a.4xlarge" 136 | , "r5a.8xlarge" 137 | , "r5a.12xlarge" 138 | , "r5a.16xlarge" 139 | , "r5a.24xlarge" 140 | , "r5b.large" 141 | , "r5b.xlarge" 142 | , "r5b.2xlarge" 143 | , "r5b.4xlarge" 144 | , "r5b.8xlarge" 145 | , "r5b.12xlarge" 146 | , "r5b.16xlarge" 147 | , "r5b.24xlarge" 148 | , "r5b.metal" 149 | , "r5d.large" 150 | , "r5d.xlarge" 151 | , "r5d.2xlarge" 152 | , "r5d.4xlarge" 153 | , "r5d.8xlarge" 154 | , "r5d.12xlarge" 155 | , "r5d.16xlarge" 156 | , "r5d.24xlarge" 157 | , "r5d.metal" 158 | , "r5ad.large" 159 | , "r5ad.xlarge" 160 | , "r5ad.2xlarge" 161 | , "r5ad.4xlarge" 162 | , "r5ad.8xlarge" 163 | , "r5ad.12xlarge" 164 | , "r5ad.16xlarge" 165 | , "r5ad.24xlarge" 166 | , "r6g.metal" 167 | , "r6g.medium" 168 | , "r6g.large" 169 | , "r6g.xlarge" 170 | , "r6g.2xlarge" 171 | , "r6g.4xlarge" 172 | , "r6g.8xlarge" 173 | , "r6g.12xlarge" 174 | , "r6g.16xlarge" 175 | , "r6gd.metal" 176 | , "r6gd.medium" 177 | , "r6gd.large" 178 | , "r6gd.xlarge" 179 | , "r6gd.2xlarge" 180 | , "r6gd.4xlarge" 181 | , "r6gd.8xlarge" 182 | , "r6gd.12xlarge" 183 | , "r6gd.16xlarge" 184 | , "x1.16xlarge" 185 | , "x1.32xlarge" 186 | , "x1e.xlarge" 187 | , "x1e.2xlarge" 188 | , "x1e.4xlarge" 189 | , "x1e.8xlarge" 190 | , "x1e.16xlarge" 191 | , "x1e.32xlarge" 192 | , "i2.xlarge" 193 | , "i2.2xlarge" 194 | , "i2.4xlarge" 195 | , "i2.8xlarge" 196 | , "i3.large" 197 | , "i3.xlarge" 198 | , "i3.2xlarge" 199 | , "i3.4xlarge" 200 | , "i3.8xlarge" 201 | , "i3.16xlarge" 202 | , "i3.metal" 203 | , "i3en.large" 204 | , "i3en.xlarge" 205 | , "i3en.2xlarge" 206 | , "i3en.3xlarge" 207 | , "i3en.6xlarge" 208 | , "i3en.12xlarge" 209 | , "i3en.24xlarge" 210 | , "i3en.metal" 211 | , "hi1.4xlarge" 212 | , "hs1.8xlarge" 213 | , "c1.medium" 214 | , "c1.xlarge" 215 | , "c3.large" 216 | , "c3.xlarge" 217 | , "c3.2xlarge" 218 | , "c3.4xlarge" 219 | , "c3.8xlarge" 220 | , "c4.large" 221 | , "c4.xlarge" 222 | , "c4.2xlarge" 223 | , "c4.4xlarge" 224 | , "c4.8xlarge" 225 | , "c5.large" 226 | , "c5.xlarge" 227 | , "c5.2xlarge" 228 | , "c5.4xlarge" 229 | , "c5.9xlarge" 230 | , "c5.12xlarge" 231 | , "c5.18xlarge" 232 | , "c5.24xlarge" 233 | , "c5.metal" 234 | , "c5a.large" 235 | , "c5a.xlarge" 236 | , "c5a.2xlarge" 237 | , "c5a.4xlarge" 238 | , "c5a.8xlarge" 239 | , "c5a.12xlarge" 240 | , "c5a.16xlarge" 241 | , "c5a.24xlarge" 242 | , "c5ad.large" 243 | , "c5ad.xlarge" 244 | , "c5ad.2xlarge" 245 | , "c5ad.4xlarge" 246 | , "c5ad.8xlarge" 247 | , "c5ad.12xlarge" 248 | , "c5ad.16xlarge" 249 | , "c5ad.24xlarge" 250 | , "c5d.large" 251 | , "c5d.xlarge" 252 | , "c5d.2xlarge" 253 | , "c5d.4xlarge" 254 | , "c5d.9xlarge" 255 | , "c5d.12xlarge" 256 | , "c5d.18xlarge" 257 | , "c5d.24xlarge" 258 | , "c5d.metal" 259 | , "c5n.large" 260 | , "c5n.xlarge" 261 | , "c5n.2xlarge" 262 | , "c5n.4xlarge" 263 | , "c5n.9xlarge" 264 | , "c5n.18xlarge" 265 | , "c5n.metal" 266 | , "c6g.metal" 267 | , "c6g.medium" 268 | , "c6g.large" 269 | , "c6g.xlarge" 270 | , "c6g.2xlarge" 271 | , "c6g.4xlarge" 272 | , "c6g.8xlarge" 273 | , "c6g.12xlarge" 274 | , "c6g.16xlarge" 275 | , "c6gd.metal" 276 | , "c6gd.medium" 277 | , "c6gd.large" 278 | , "c6gd.xlarge" 279 | , "c6gd.2xlarge" 280 | , "c6gd.4xlarge" 281 | , "c6gd.8xlarge" 282 | , "c6gd.12xlarge" 283 | , "c6gd.16xlarge" 284 | , "c6gn.medium" 285 | , "c6gn.large" 286 | , "c6gn.xlarge" 287 | , "c6gn.2xlarge" 288 | , "c6gn.4xlarge" 289 | , "c6gn.8xlarge" 290 | , "c6gn.12xlarge" 291 | , "c6gn.16xlarge" 292 | , "cc1.4xlarge" 293 | , "cc2.8xlarge" 294 | , "g2.2xlarge" 295 | , "g2.8xlarge" 296 | , "g3.4xlarge" 297 | , "g3.8xlarge" 298 | , "g3.16xlarge" 299 | , "g3s.xlarge" 300 | , "g4ad.4xlarge" 301 | , "g4ad.8xlarge" 302 | , "g4ad.16xlarge" 303 | , "g4dn.xlarge" 304 | , "g4dn.2xlarge" 305 | , "g4dn.4xlarge" 306 | , "g4dn.8xlarge" 307 | , "g4dn.12xlarge" 308 | , "g4dn.16xlarge" 309 | , "g4dn.metal" 310 | , "cg1.4xlarge" 311 | , "p2.xlarge" 312 | , "p2.8xlarge" 313 | , "p2.16xlarge" 314 | , "p3.2xlarge" 315 | , "p3.8xlarge" 316 | , "p3.16xlarge" 317 | , "p3dn.24xlarge" 318 | , "p4d.24xlarge" 319 | , "d2.xlarge" 320 | , "d2.2xlarge" 321 | , "d2.4xlarge" 322 | , "d2.8xlarge" 323 | , "d3.xlarge" 324 | , "d3.2xlarge" 325 | , "d3.4xlarge" 326 | , "d3.8xlarge" 327 | , "d3en.xlarge" 328 | , "d3en.2xlarge" 329 | , "d3en.4xlarge" 330 | , "d3en.6xlarge" 331 | , "d3en.8xlarge" 332 | , "d3en.12xlarge" 333 | , "f1.2xlarge" 334 | , "f1.4xlarge" 335 | , "f1.16xlarge" 336 | , "m5.large" 337 | , "m5.xlarge" 338 | , "m5.2xlarge" 339 | , "m5.4xlarge" 340 | , "m5.8xlarge" 341 | , "m5.12xlarge" 342 | , "m5.16xlarge" 343 | , "m5.24xlarge" 344 | , "m5.metal" 345 | , "m5a.large" 346 | , "m5a.xlarge" 347 | , "m5a.2xlarge" 348 | , "m5a.4xlarge" 349 | , "m5a.8xlarge" 350 | , "m5a.12xlarge" 351 | , "m5a.16xlarge" 352 | , "m5a.24xlarge" 353 | , "m5d.large" 354 | , "m5d.xlarge" 355 | , "m5d.2xlarge" 356 | , "m5d.4xlarge" 357 | , "m5d.8xlarge" 358 | , "m5d.12xlarge" 359 | , "m5d.16xlarge" 360 | , "m5d.24xlarge" 361 | , "m5d.metal" 362 | , "m5ad.large" 363 | , "m5ad.xlarge" 364 | , "m5ad.2xlarge" 365 | , "m5ad.4xlarge" 366 | , "m5ad.8xlarge" 367 | , "m5ad.12xlarge" 368 | , "m5ad.16xlarge" 369 | , "m5ad.24xlarge" 370 | , "m5zn.large" 371 | , "m5zn.xlarge" 372 | , "m5zn.2xlarge" 373 | , "m5zn.3xlarge" 374 | , "m5zn.6xlarge" 375 | , "m5zn.12xlarge" 376 | , "m5zn.metal" 377 | , "h1.2xlarge" 378 | , "h1.4xlarge" 379 | , "h1.8xlarge" 380 | , "h1.16xlarge" 381 | , "z1d.large" 382 | , "z1d.xlarge" 383 | , "z1d.2xlarge" 384 | , "z1d.3xlarge" 385 | , "z1d.6xlarge" 386 | , "z1d.12xlarge" 387 | , "z1d.metal" 388 | , "u-6tb1.56xlarge" 389 | , "u-6tb1.112xlarge" 390 | , "u-9tb1.112xlarge" 391 | , "u-12tb1.112xlarge" 392 | , "u-6tb1.metal" 393 | , "u-9tb1.metal" 394 | , "u-12tb1.metal" 395 | , "u-18tb1.metal" 396 | , "u-24tb1.metal" 397 | , "a1.medium" 398 | , "a1.large" 399 | , "a1.xlarge" 400 | , "a1.2xlarge" 401 | , "a1.4xlarge" 402 | , "a1.metal" 403 | , "m5dn.large" 404 | , "m5dn.xlarge" 405 | , "m5dn.2xlarge" 406 | , "m5dn.4xlarge" 407 | , "m5dn.8xlarge" 408 | , "m5dn.12xlarge" 409 | , "m5dn.16xlarge" 410 | , "m5dn.24xlarge" 411 | , "m5n.large" 412 | , "m5n.xlarge" 413 | , "m5n.2xlarge" 414 | , "m5n.4xlarge" 415 | , "m5n.8xlarge" 416 | , "m5n.12xlarge" 417 | , "m5n.16xlarge" 418 | , "m5n.24xlarge" 419 | , "r5dn.large" 420 | , "r5dn.xlarge" 421 | , "r5dn.2xlarge" 422 | , "r5dn.4xlarge" 423 | , "r5dn.8xlarge" 424 | , "r5dn.12xlarge" 425 | , "r5dn.16xlarge" 426 | , "r5dn.24xlarge" 427 | , "r5n.large" 428 | , "r5n.xlarge" 429 | , "r5n.2xlarge" 430 | , "r5n.4xlarge" 431 | , "r5n.8xlarge" 432 | , "r5n.12xlarge" 433 | , "r5n.16xlarge" 434 | , "r5n.24xlarge" 435 | , "inf1.xlarge" 436 | , "inf1.2xlarge" 437 | , "inf1.6xlarge" 438 | , "inf1.24xlarge" 439 | , "m6g.metal" 440 | , "m6g.medium" 441 | , "m6g.large" 442 | , "m6g.xlarge" 443 | , "m6g.2xlarge" 444 | , "m6g.4xlarge" 445 | , "m6g.8xlarge" 446 | , "m6g.12xlarge" 447 | , "m6g.16xlarge" 448 | , "m6gd.metal" 449 | , "m6gd.medium" 450 | , "m6gd.large" 451 | , "m6gd.xlarge" 452 | , "m6gd.2xlarge" 453 | , "m6gd.4xlarge" 454 | , "m6gd.8xlarge" 455 | , "m6gd.12xlarge" 456 | , "m6gd.16xlarge" 457 | , "mac1.metal" 458 | , "x2gd.medium" 459 | , "x2gd.large" 460 | , "x2gd.xlarge" 461 | , "x2gd.2xlarge" 462 | , "x2gd.4xlarge" 463 | , "x2gd.8xlarge" 464 | , "x2gd.12xlarge" 465 | , "x2gd.16xlarge" 466 | , "x2gd.metal" 467 | ] 468 | 469 | -- replace hard coded array with the describe-regions call 470 | -- aws ec2 describe-regions --all-regions --query "Regions[].RegionName" 471 | regions :: Array String 472 | regions = 473 | [ "eu-north-1" 474 | , "ap-south-1" 475 | , "eu-west-3" 476 | , "eu-west-2" 477 | , "eu-west-1" 478 | , "ap-northeast-3" 479 | , "ap-northeast-2" 480 | , "ap-northeast-1" 481 | , "sa-east-1" 482 | , "ca-central-1" 483 | , "ap-southeast-1" 484 | , "ap-southeast-2" 485 | , "eu-central-1" 486 | , "us-east-1" 487 | , "us-east-2" 488 | , "us-west-1" 489 | , "us-west-2" 490 | ] 491 | -------------------------------------------------------------------------------- /src/AWS/CloudWatchLogs/CloudwatchLogs.purs: -------------------------------------------------------------------------------- 1 | module AWS.CloudWatchLogs 2 | ( CloudWatchLogs 3 | , DescribeLogGroupsResponse 4 | , LogGroup 5 | , RetentionSettings 6 | , toRetention 7 | , LogGroupName(..) 8 | , ExportTaskParams 9 | , Destination(..) 10 | , From(..) 11 | , To(..) 12 | , deleteRetentionPolicy 13 | , putRetentionPolicy 14 | , retentionToInt 15 | , describeLogGroups 16 | , createExportTask 17 | , makeClient 18 | , RetentionInDays(..) 19 | , TagContainer 20 | , listTagsLogGroup 21 | , describeAllLogGroups 22 | , describeLogStreams 23 | ) where 24 | 25 | import Prelude 26 | import AWS.Core.Client (makeClientHelper) 27 | import AWS.Core.Types (DefaultClientProps, Tags) 28 | import AWS.Core.Util (handleError, unfoldrM1) 29 | import Control.Monad.Error.Class (throwError) 30 | import Control.Promise (Promise) 31 | import Control.Promise as Promise 32 | import Data.Argonaut (Json) 33 | import Data.Argonaut.Decode (class DecodeJson, decodeJson) 34 | import Data.Argonaut.Encode (class EncodeJson) 35 | import Data.Argonaut.Encode.Encoders (encodeString) 36 | import Data.Bifunctor (lmap) 37 | import Data.Either (Either) 38 | import Data.Function.Uncurried (Fn2, Fn3, Fn5, runFn2, runFn3, runFn5) 39 | import Data.Maybe (Maybe(..)) 40 | import Data.Newtype (class Newtype) 41 | import Data.Nullable (Nullable, toNullable) 42 | import Data.Nullable as Nullable 43 | import Data.Tuple (Tuple(..)) 44 | import Effect (Effect) 45 | import Effect.Aff (Aff) 46 | import Effect.Class (liftEffect) 47 | import Effect.Exception (error) 48 | import Justifill (justifillVia) 49 | import Justifill.Fillable (class Fillable) 50 | import Justifill.Justifiable (class Justifiable) 51 | import Type.Proxy (Proxy(..)) 52 | 53 | foreign import data CloudWatchLogs :: Type 54 | 55 | foreign import newCloudWatchLogs :: Json -> (Effect CloudWatchLogs) 56 | 57 | makeClient :: 58 | forall r via. 59 | Justifiable { | r } { | via } => 60 | Fillable { | via } DefaultClientProps => 61 | { | r } -> 62 | Effect CloudWatchLogs 63 | makeClient r = makeClientHelper newCloudWatchLogs props 64 | where 65 | viaProxy :: Proxy { | via } 66 | viaProxy = Proxy 67 | 68 | props :: DefaultClientProps 69 | props = justifillVia viaProxy r 70 | 71 | newtype LogGroupName 72 | = LogGroupName String 73 | 74 | newtype Destination 75 | = Destination String 76 | 77 | newtype From 78 | = From Number 79 | 80 | newtype To 81 | = To Number 82 | 83 | derive instance ntLogGroupName :: Newtype LogGroupName _ 84 | 85 | derive newtype instance showLogGroupName :: Show LogGroupName 86 | 87 | derive newtype instance encodeLogGroupName :: EncodeJson LogGroupName 88 | 89 | derive newtype instance decodeLogGroupName :: DecodeJson LogGroupName 90 | 91 | data RetentionInDays 92 | = Retention1Day 93 | | Retention3Days 94 | | Retention5Days 95 | | Retention1Week 96 | | Retention2Weeks 97 | | Retention1Month 98 | | Retention2Months 99 | | Retention3Months 100 | | Retention4Months 101 | | Retention5Months 102 | | Retention6Months 103 | | Retention12Months 104 | | Retention13Months 105 | | Retention18Months 106 | | Retention24Months 107 | | Retention60Months 108 | | Retention120Months 109 | | NoRetention 110 | 111 | instance encodeRetentionInDays :: EncodeJson RetentionInDays where 112 | encodeJson Retention1Day = encodeString "1" 113 | encodeJson Retention3Days = encodeString "3" 114 | encodeJson Retention5Days = encodeString "5" 115 | encodeJson Retention1Week = encodeString "7" 116 | encodeJson Retention2Weeks = encodeString "14" 117 | encodeJson Retention1Month = encodeString "30" 118 | encodeJson Retention2Months = encodeString "60" 119 | encodeJson Retention3Months = encodeString "90" 120 | encodeJson Retention4Months = encodeString "120" 121 | encodeJson Retention5Months = encodeString "150" 122 | encodeJson Retention6Months = encodeString "180" 123 | encodeJson Retention12Months = encodeString "365" 124 | encodeJson Retention13Months = encodeString "400" 125 | encodeJson Retention18Months = encodeString "545" 126 | encodeJson Retention24Months = encodeString "731" 127 | encodeJson Retention60Months = encodeString "1827" 128 | encodeJson Retention120Months = encodeString "3653" 129 | encodeJson NoRetention = encodeString "no retention" 130 | 131 | retentionToInt :: RetentionInDays -> Maybe Int 132 | retentionToInt retention = case retention of 133 | Retention1Day -> Just (1) 134 | Retention3Days -> Just (3) 135 | Retention5Days -> Just (5) 136 | Retention1Week -> Just (7) 137 | Retention2Weeks -> Just (14) 138 | Retention1Month -> Just (30) 139 | Retention2Months -> Just (60) 140 | Retention3Months -> Just (90) 141 | Retention4Months -> Just (120) 142 | Retention5Months -> Just (150) 143 | Retention6Months -> Just (180) 144 | Retention12Months -> Just (365) 145 | Retention13Months -> Just (400) 146 | Retention18Months -> Just (545) 147 | Retention24Months -> Just (731) 148 | Retention60Months -> Just (1827) 149 | Retention120Months -> Just (3653) 150 | NoRetention -> Nothing 151 | 152 | toRetention :: Maybe Int -> RetentionInDays 153 | toRetention retention = case retention of 154 | Just (1) -> Retention1Day 155 | Just (3) -> Retention3Days 156 | Just (5) -> Retention5Days 157 | Just (7) -> Retention1Week 158 | Just (14) -> Retention2Weeks 159 | Just (30) -> Retention1Month 160 | Just (60) -> Retention2Months 161 | Just (90) -> Retention3Months 162 | Just (120) -> Retention4Months 163 | Just (150) -> Retention5Months 164 | Just (180) -> Retention6Months 165 | Just (365) -> Retention12Months 166 | Just (400) -> Retention13Months 167 | Just (545) -> Retention18Months 168 | Just (731) -> Retention24Months 169 | Just (1827) -> Retention60Months 170 | Just (3653) -> Retention120Months 171 | Just (_) -> NoRetention 172 | Nothing -> NoRetention 173 | 174 | type RetentionSettings 175 | = { logGroupName :: LogGroupName 176 | , retentionInDays :: RetentionInDays 177 | } 178 | 179 | type InternalDescribeLogGroupsResponse 180 | = { logGroups :: Array InternalLogGroup 181 | , nextToken :: Nullable String 182 | } 183 | 184 | type DescribeLogGroupsResponse 185 | = { logGroups :: Array LogGroup 186 | , nextToken :: Maybe String 187 | } 188 | 189 | type InternalLogGroup 190 | = { arn :: Nullable String 191 | , creationTime :: Nullable Number 192 | , kmsKeyId :: Nullable String 193 | , logGroupName :: Nullable String 194 | , metricFilterCount :: Nullable Number 195 | , retentionInDays :: Nullable Number 196 | , storedBytes :: Nullable Number 197 | } 198 | 199 | -- todo: Number to TimeStamp 200 | type LogGroup 201 | = { creationTime :: Maybe Number 202 | , logGroupName :: Maybe String 203 | , retentionInDays :: Maybe Number 204 | , storedBytes :: Maybe Number 205 | } 206 | 207 | type InternalDescribeLogStreamsResponse 208 | = { logStreams :: Array InternalLogStream 209 | , nextToken :: Nullable String 210 | } 211 | 212 | type InternalLogStream 213 | = { creationTime :: Nullable Number 214 | , firstEventTimestamp :: Nullable Number 215 | , lastEventTimestamp :: Nullable Number 216 | , lastIngestionTime :: Nullable Number 217 | } 218 | 219 | -- todo: Number to TimeStamp 220 | type LogStream 221 | = { creationTime :: Maybe Number 222 | , firstEventTimestamp :: Maybe Number 223 | , lastEventTimestamp :: Maybe Number 224 | , lastIngestionTime :: Maybe Number 225 | } 226 | 227 | type DescribeLogStreamsResponse 228 | = { logStreams :: Array LogStream 229 | , nextToken :: Maybe String 230 | } 231 | 232 | type InternalDescribeLogStreamsParams 233 | = { logGroupName :: String 234 | , nextToken :: Nullable String 235 | } 236 | 237 | type DescribeLogStreamsParams 238 | = { logGroupName :: String 239 | , nextToken :: Maybe String 240 | } 241 | 242 | type InternalDescribeLogGroupsParams 243 | = { nextToken :: Nullable String } 244 | 245 | type DescribeLogGroupsParams 246 | = { nextToken :: Maybe String } 247 | 248 | type ExportTaskParams 249 | = { destination :: Destination 250 | , from :: From 251 | , logGroupName :: LogGroupName 252 | , to :: To 253 | } 254 | 255 | foreign import describeLogGroupsImpl :: Fn2 CloudWatchLogs InternalDescribeLogGroupsParams (Effect (Promise InternalDescribeLogGroupsResponse)) 256 | 257 | describeLogGroups :: 258 | CloudWatchLogs -> 259 | DescribeLogGroupsParams -> 260 | Aff DescribeLogGroupsResponse 261 | describeLogGroups cloudWatchLogs params = liftEffect (curried cloudWatchLogs internalParams) >>= Promise.toAff <#> toExternal 262 | where 263 | toExternal :: InternalDescribeLogGroupsResponse -> DescribeLogGroupsResponse 264 | toExternal { logGroups: internal, nextToken } = { logGroups: internal <#> toExternalLogGroup, nextToken: Nullable.toMaybe nextToken } 265 | 266 | toExternalLogGroup :: InternalLogGroup -> LogGroup 267 | toExternalLogGroup internal = 268 | { creationTime: Nullable.toMaybe internal.creationTime 269 | , logGroupName: Nullable.toMaybe internal.logGroupName 270 | , retentionInDays: Nullable.toMaybe internal.retentionInDays 271 | , storedBytes: Nullable.toMaybe internal.storedBytes 272 | } 273 | 274 | internalParams = { nextToken: Nullable.toNullable params.nextToken } 275 | 276 | curried :: CloudWatchLogs -> InternalDescribeLogGroupsParams -> Effect (Promise InternalDescribeLogGroupsResponse) 277 | curried = runFn2 describeLogGroupsImpl 278 | 279 | describeAllLogGroups :: CloudWatchLogs -> Aff (Array LogGroup) 280 | describeAllLogGroups api = do 281 | initial <- describeLogGroups api { nextToken: Nothing } 282 | unfoldrM1 initial.nextToken 283 | ( \(currentNextToken :: String) -> do 284 | { logGroups, nextToken } <- describeLogGroups api { nextToken: Just currentNextToken } 285 | pure $ Tuple logGroups nextToken 286 | ) 287 | <#> (\remaining -> (pure initial.logGroups <> remaining) # join) 288 | 289 | foreign import describeLogStreamsImpl :: Fn2 CloudWatchLogs InternalDescribeLogStreamsParams (Effect (Promise InternalDescribeLogStreamsResponse)) 290 | 291 | describeLogStreams :: 292 | CloudWatchLogs -> 293 | DescribeLogStreamsParams -> 294 | Aff DescribeLogStreamsResponse 295 | describeLogStreams cloudWatchLogs params = liftEffect (curried cloudWatchLogs internalParams) >>= Promise.toAff <#> toExternal 296 | where 297 | toExternal :: InternalDescribeLogStreamsResponse -> DescribeLogStreamsResponse 298 | toExternal { logStreams: internal, nextToken } = { logStreams: internal <#> toExternalLogStream, nextToken: Nullable.toMaybe nextToken } 299 | 300 | toExternalLogStream :: InternalLogStream -> LogStream 301 | toExternalLogStream internal = 302 | { creationTime: Nullable.toMaybe internal.creationTime 303 | , firstEventTimestamp: Nullable.toMaybe internal.firstEventTimestamp 304 | , lastEventTimestamp: Nullable.toMaybe internal.lastEventTimestamp 305 | , lastIngestionTime: Nullable.toMaybe internal.lastIngestionTime 306 | } 307 | 308 | internalParams = 309 | { logGroupName: params.logGroupName 310 | , nextToken: Nullable.toNullable params.nextToken 311 | } 312 | 313 | curried :: CloudWatchLogs -> InternalDescribeLogStreamsParams -> Effect (Promise InternalDescribeLogStreamsResponse) 314 | curried = (runFn2 describeLogStreamsImpl) 315 | 316 | foreign import putRetentionPolicyImpl :: Fn3 CloudWatchLogs String (Nullable Int) (Effect (Promise Unit)) 317 | 318 | foreign import deleteRetentionPolicyImpl :: Fn2 CloudWatchLogs String (Effect (Promise Unit)) 319 | 320 | -- | Sets the retention policy for the log group. 321 | -- | For setting NoRetention aka `Never Expire` use `deleteRetentionPolicy`. 322 | putRetentionPolicy :: CloudWatchLogs -> LogGroupName -> RetentionInDays -> Aff Unit 323 | putRetentionPolicy cw (LogGroupName name) NoRetention = throwError $ error "Setting RetentionPolicy to NoRetention is not allowed. Use deleteRetentionPolicy instead." 324 | 325 | putRetentionPolicy cw (LogGroupName name) retention = 326 | Promise.toAffE 327 | $ runFn3 putRetentionPolicyImpl cw name (toNullable $ retentionToInt $ retention) 328 | 329 | -- | Deletes the retention policy from the log group, i.e. set's it to NoRetention aka `Never Expire`. 330 | -- | For setting a retention policy use `putRetentionPolicy` instead. 331 | deleteRetentionPolicy :: CloudWatchLogs -> LogGroupName -> Aff Unit 332 | deleteRetentionPolicy cw (LogGroupName name) = 333 | Promise.toAffE 334 | $ runFn2 deleteRetentionPolicyImpl cw name 335 | 336 | type CreateExportTaskResponse 337 | = { taskId :: String } 338 | 339 | foreign import createExportTaskImpl :: Fn5 CloudWatchLogs String Number String Number (Effect (Promise CreateExportTaskResponse)) 340 | 341 | createExportTask :: CloudWatchLogs -> Destination -> From -> LogGroupName -> To -> Aff CreateExportTaskResponse 342 | createExportTask cw (Destination destination) (From from) (LogGroupName logGroupName) (To to) = 343 | Promise.toAffE 344 | $ runFn5 createExportTaskImpl cw destination from logGroupName to 345 | 346 | foreign import listTagsLogGroupImpl :: Fn2 CloudWatchLogs String (Effect (Promise Json)) 347 | 348 | type TagContainer 349 | = { tags :: Tags 350 | } 351 | 352 | listTagsLogGroup :: CloudWatchLogs -> LogGroupName -> Aff (Either String TagContainer) 353 | listTagsLogGroup cw (LogGroupName name) = liftEffect curried >>= Promise.toAff <#> parse 354 | where 355 | parse :: Json -> Either String TagContainer 356 | parse str = (decodeJson str) # lmap handleError 357 | 358 | curried :: Effect (Promise Json) 359 | curried = runFn2 listTagsLogGroupImpl cw name 360 | --------------------------------------------------------------------------------