├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE ├── README.md ├── aws-java-sdk ├── aspectjrt-1.8.2.jar ├── aspectjweaver.jar ├── aws-java-sdk-1.11.365.jar ├── aws-swf-build-tools-1.1.jar ├── commons-codec-1.10.jar ├── commons-logging-1.1.3.jar ├── freemarker-2.3.9.jar ├── httpclient-4.5.5.jar ├── httpcore-4.4.9.jar ├── ion-java-1.0.2.jar ├── jackson-annotations-2.6.0.jar ├── jackson-core-2.6.7.jar ├── jackson-databind-2.6.7.1.jar ├── jackson-dataformat-cbor-2.6.7.jar ├── javax.mail-api-1.4.6.jar ├── jmespath-java-1.11.365.jar ├── joda-time-2.8.1.jar ├── netty-buffer-4.1.17.Final.jar ├── netty-codec-4.1.17.Final.jar ├── netty-codec-http-4.1.17.Final.jar ├── netty-common-4.1.17.Final.jar ├── netty-handler-4.1.17.Final.jar ├── netty-resolver-4.1.17.Final.jar ├── netty-transport-4.1.17.Final.jar ├── spring-beans-3.0.7.RELEASE.jar ├── spring-context-3.0.7.RELEASE.jar ├── spring-core-3.0.7.RELEASE.jar └── spring-test-3.0.7.RELEASE.jar ├── aws.cfc ├── box.json ├── dynamodb.cfc ├── elb.cfc ├── lambda.cfc ├── opsworks.cfc ├── route53.cfc ├── s3.cfc ├── ses.cfc └── tests ├── Application.cfc ├── aws.cfc ├── dynamodb.cfc ├── elb.cfc ├── index.cfm ├── lambda.cfc ├── route53.cfc ├── runtests.cfm ├── s3.cfc └── ses.cfc /.gitignore: -------------------------------------------------------------------------------- 1 | testbox 2 | tests/.exitcode 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: required 3 | 4 | services: 5 | - docker 6 | 7 | before_install: 8 | - docker build -t mso-net/lucee-aws . 9 | 10 | script: 11 | - docker run -e "aws_accountid=$aws_accountid" -e "aws_secretkey=$aws_secretkey" -e "dynamodb_table=$dynamodb_table" -e "elb_name=$elb_name" -e "elb_region=$elb_region" -e "lambda_method=$lambda_method" -e "route53_tld=$route53_tld" -e "s3_bucket=$s3_bucket" -e "ses_from=$ses_from" -e "ses_to=$ses_to" mso-net/lucee-aws 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ortussolutions/commandbox:latest 2 | 3 | MAINTAINER Simon Hooker 4 | 5 | COPY ./ ${BUILD_DIR}/ 6 | WORKDIR ${BUILD_DIR} 7 | RUN box install 8 | 9 | CMD cd $BUILD_DIR/tests && \ 10 | box $BUILD_DIR/tests/runtests.cfm && \ 11 | exitcode=$(<.exitcode) && \ 12 | exit $exitcode 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 mso 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lucee-aws 2 | 3 | [![Build Status](https://travis-ci.org/mso-net/lucee-aws.svg?branch=master)](https://travis-ci.org/mso-net/lucee-aws) 4 | 5 | Lucee extension to provide simpler access to common AWS commands through the AWS SDK. 6 | 7 | ## Installation 8 | 9 | The easiest way to install this at present is to use CommandBox. To install with CommandBox 2.1+ simply do the following. 10 | 11 | `box install mso-net/lucee-aws --production` 12 | 13 | The contents of /aws-java-sdk are just the jar files from [http://sdk-for-java.amazonwebservices.com/latest/aws-java-sdk.zip](http://sdk-for-java.amazonwebservices.com/latest/aws-java-sdk.zip). I am looking for a better way of handling this dependency but for now I'm concentrating on other tasks. 14 | 15 | **Important** There are currently some conflicts between the AWS Java SDK and Lucee. At present I would advise replacing the Lucee/CommandBox version of joda-time.jar with the version within the AWS Java SDK. If you don't do this you will see issues especially with S3. Additionally the javax-mailer jar conflicts with the one in Lucee, in this case you can delete the one from the AWS Java SDK - I don't think I'm actually making use of that yet. 16 | 17 | ## Running unit tests 18 | 19 | The unit tests within lucee-aws may be run using Docker. To do so you will need to configure various environment variables with your own values - setting up this environment is not something I have scripts for at present though. 20 | 21 | It can be built and run by executing the following commands. 22 | 23 | ``` 24 | docker build -t mso-net/lucee-aws . 25 | docker run -e "aws_accountid=$aws_accountid" -e "aws_secretkey=$aws_secretkey" -e "dynamodb_table=$dynamodb_table" -e "elb_name=$elb_name" -e "elb_region=$elb_region" -e "lambda_method=$lambda_method" -e "route53_tld=$route53_tld" -e "s3_bucket=$s3_bucket" -e "ses_from=$ses_from" -e "ses_to=$ses_to" mso-net/lucee-aws 26 | ``` 27 | 28 | 29 | ## Usage 30 | 31 | ### S3 32 | Example for S3 33 | 34 | ``` 35 | s3 = new aws.s3( 36 | account = 'account_id', 37 | secret = 'secret', 38 | bucket = 'bucket_name' 39 | ); 40 | 41 | s3.getObject( 'path/to/something.ext' ); 42 | s3.putObject( 'path/to/something.ext' , 'data:image/png;base64,data_base64_encoded_here' ); 43 | s3.deleteObject( 'path/to/something.ext' ); 44 | ``` 45 | 46 | ## Additional reading 47 | 48 | - [Strayegg lucee-aws blog](http://www.strayegg.com/tag/lucee-aws/) 49 | - [AWS SDK for Java API documentation](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/index.html) 50 | -------------------------------------------------------------------------------- /aws-java-sdk/aspectjrt-1.8.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/aspectjrt-1.8.2.jar -------------------------------------------------------------------------------- /aws-java-sdk/aspectjweaver.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/aspectjweaver.jar -------------------------------------------------------------------------------- /aws-java-sdk/aws-java-sdk-1.11.365.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/aws-java-sdk-1.11.365.jar -------------------------------------------------------------------------------- /aws-java-sdk/aws-swf-build-tools-1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/aws-swf-build-tools-1.1.jar -------------------------------------------------------------------------------- /aws-java-sdk/commons-codec-1.10.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/commons-codec-1.10.jar -------------------------------------------------------------------------------- /aws-java-sdk/commons-logging-1.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/commons-logging-1.1.3.jar -------------------------------------------------------------------------------- /aws-java-sdk/freemarker-2.3.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/freemarker-2.3.9.jar -------------------------------------------------------------------------------- /aws-java-sdk/httpclient-4.5.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/httpclient-4.5.5.jar -------------------------------------------------------------------------------- /aws-java-sdk/httpcore-4.4.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/httpcore-4.4.9.jar -------------------------------------------------------------------------------- /aws-java-sdk/ion-java-1.0.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/ion-java-1.0.2.jar -------------------------------------------------------------------------------- /aws-java-sdk/jackson-annotations-2.6.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/jackson-annotations-2.6.0.jar -------------------------------------------------------------------------------- /aws-java-sdk/jackson-core-2.6.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/jackson-core-2.6.7.jar -------------------------------------------------------------------------------- /aws-java-sdk/jackson-databind-2.6.7.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/jackson-databind-2.6.7.1.jar -------------------------------------------------------------------------------- /aws-java-sdk/jackson-dataformat-cbor-2.6.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/jackson-dataformat-cbor-2.6.7.jar -------------------------------------------------------------------------------- /aws-java-sdk/javax.mail-api-1.4.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/javax.mail-api-1.4.6.jar -------------------------------------------------------------------------------- /aws-java-sdk/jmespath-java-1.11.365.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/jmespath-java-1.11.365.jar -------------------------------------------------------------------------------- /aws-java-sdk/joda-time-2.8.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/joda-time-2.8.1.jar -------------------------------------------------------------------------------- /aws-java-sdk/netty-buffer-4.1.17.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/netty-buffer-4.1.17.Final.jar -------------------------------------------------------------------------------- /aws-java-sdk/netty-codec-4.1.17.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/netty-codec-4.1.17.Final.jar -------------------------------------------------------------------------------- /aws-java-sdk/netty-codec-http-4.1.17.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/netty-codec-http-4.1.17.Final.jar -------------------------------------------------------------------------------- /aws-java-sdk/netty-common-4.1.17.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/netty-common-4.1.17.Final.jar -------------------------------------------------------------------------------- /aws-java-sdk/netty-handler-4.1.17.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/netty-handler-4.1.17.Final.jar -------------------------------------------------------------------------------- /aws-java-sdk/netty-resolver-4.1.17.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/netty-resolver-4.1.17.Final.jar -------------------------------------------------------------------------------- /aws-java-sdk/netty-transport-4.1.17.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/netty-transport-4.1.17.Final.jar -------------------------------------------------------------------------------- /aws-java-sdk/spring-beans-3.0.7.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/spring-beans-3.0.7.RELEASE.jar -------------------------------------------------------------------------------- /aws-java-sdk/spring-context-3.0.7.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/spring-context-3.0.7.RELEASE.jar -------------------------------------------------------------------------------- /aws-java-sdk/spring-core-3.0.7.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/spring-core-3.0.7.RELEASE.jar -------------------------------------------------------------------------------- /aws-java-sdk/spring-test-3.0.7.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mso-net/lucee-aws/fd9dc94dee95c1db55a77ab08c9fbe58e2d174fb/aws-java-sdk/spring-test-3.0.7.RELEASE.jar -------------------------------------------------------------------------------- /aws.cfc: -------------------------------------------------------------------------------- 1 | component accessors=true { 2 | 3 | property name='credentials' type='com.amazonaws.auth.AWSCredentialsProvider' getter=false setter=false; 4 | property name='regions' type='com.amazonaws.regions.Regions' getter=false setter=false; 5 | 6 | public aws function init( 7 | string account, 8 | string secret 9 | ) { 10 | var potential_credentials = [ 11 | CreateAWSObject( 'auth.InstanceProfileCredentialsProvider' ) 12 | .init( false ) 13 | ]; 14 | 15 | if ( 16 | IsDefined( 'arguments.account' ) 17 | && IsDefined( 'arguments.secret' ) 18 | && arguments.account.len() > 0 19 | && arguments.secret.len() > 0 20 | ) { 21 | potential_credentials.add( 22 | CreateAWSObject( 'auth.AWSStaticCredentialsProvider' ) 23 | .init( CreateAWSObject( 'auth.BasicAWSCredentials' ).init( 24 | arguments.account, 25 | arguments.secret 26 | ) ) 27 | ); 28 | } 29 | 30 | var system = CreateObject( 'java' , 'java.lang.System' ); 31 | var environment = system.getenv(); 32 | 33 | if ( IsDefined( 'environment.AWS_PROFILE' ) && IsDefined( 'environment.AWS_CONFIG_FILE' ) ) { 34 | potential_credentials.add( 35 | CreateAWSObject( 'auth.profile.ProfileCredentialsProvider' ) 36 | .init( environment.AWS_CONFIG_FILE , environment.AWS_PROFILE ) 37 | ); 38 | } 39 | 40 | variables.credentials = CreateAWSObject( 'auth.AWSCredentialsProviderChain' ) 41 | .init( potential_credentials ); 42 | 43 | variables.regions = CreateAWSObject( 'regions.Regions' ); 44 | return this; 45 | } 46 | 47 | private function CreateAWSObject( 48 | required string name 49 | ) { 50 | return CreateObject( 51 | 'java', 52 | 'com.amazonaws.'&arguments.name, 53 | [ 54 | 'aws-java-sdk/aspectjrt-1.8.2.jar', 55 | 'aws-java-sdk/aspectjweaver.jar', 56 | 'aws-java-sdk/aws-java-sdk-1.11.365.jar', 57 | 'aws-java-sdk/aws-swf-build-tools-1.1.jar', 58 | 'aws-java-sdk/commons-codec-1.10.jar', 59 | 'aws-java-sdk/commons-logging-1.1.3.jar', 60 | 'aws-java-sdk/freemarker-2.3.9.jar', 61 | 'aws-java-sdk/httpclient-4.5.5.jar', 62 | 'aws-java-sdk/httpcore-4.4.9.jar', 63 | 'aws-java-sdk/ion-java-1.0.2.jar', 64 | 'aws-java-sdk/jackson-annotations-2.6.0.jar', 65 | 'aws-java-sdk/jackson-core-2.6.7.jar', 66 | 'aws-java-sdk/jackson-databind-2.6.7.1.jar', 67 | 'aws-java-sdk/jackson-dataformat-cbor-2.6.7.jar', 68 | 'aws-java-sdk/javax.mail-api-1.4.6.jar', 69 | 'aws-java-sdk/jmespath-java-1.11.365.jar', 70 | 'aws-java-sdk/joda-time-2.8.1.jar', 71 | 'aws-java-sdk/netty-buffer-4.1.17.Final.jar', 72 | 'aws-java-sdk/netty-codec-4.1.17.Final.jar', 73 | 'aws-java-sdk/netty-codec-http-4.1.17.Final.jar', 74 | 'aws-java-sdk/netty-common-4.1.17.Final.jar', 75 | 'aws-java-sdk/netty-handler-4.1.17.Final.jar', 76 | 'aws-java-sdk/netty-resolver-4.1.17.Final.jar', 77 | 'aws-java-sdk/netty-transport-4.1.17.Final.jar', 78 | 'aws-java-sdk/spring-beans-3.0.7.RELEASE.jar', 79 | 'aws-java-sdk/spring-context-3.0.7.RELEASE.jar', 80 | 'aws-java-sdk/spring-core-3.0.7.RELEASE.jar', 81 | 'aws-java-sdk/spring-test-3.0.7.RELEASE.jar' 82 | ] 83 | ); 84 | } 85 | 86 | private function getCredentials() { 87 | return variables.credentials; 88 | } 89 | 90 | private function getRegions() { 91 | return variables.regions; 92 | } 93 | 94 | public function getRegion( 95 | string region = 'eu-west-1' 96 | ) { 97 | return getRegions().fromName( 98 | arguments.region 99 | ); 100 | } 101 | 102 | private any function getMyClient() { 103 | return variables.myClient; 104 | } 105 | 106 | public function setRegion( 107 | string region = 'eu-west-1' 108 | ) { 109 | getMyClient().configureRegion( 110 | getRegion( 111 | arguments.region 112 | ) 113 | ); 114 | 115 | return this; 116 | } 117 | 118 | } -------------------------------------------------------------------------------- /box.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"Lucee AWS", 3 | "slug":"lucee-aws", 4 | "version":"0.2.0", 5 | "author":"Simon Hooker", 6 | "private":false, 7 | "packageDirectory":"aws", 8 | "license":[ 9 | { 10 | "type":"LGPL-2.1", 11 | "url":"http://opensource.org/licenses/LGPL-2.1" 12 | } 13 | ], 14 | "engines":[ 15 | { 16 | "type":"lucee", 17 | "version":">=4.5.x" 18 | } 19 | ], 20 | "devDependencies":{ 21 | "testbox":"github:Ortus-Solutions/TestBox" 22 | }, 23 | "installPaths":{ 24 | "testbox":"testbox" 25 | }, 26 | "dependencies":{ 27 | 28 | }, 29 | "ignore":[ 30 | "/tests/", 31 | "/testbox/", 32 | "/test", 33 | "/.gitignore", 34 | "/.travis.yml" 35 | ] 36 | } -------------------------------------------------------------------------------- /dynamodb.cfc: -------------------------------------------------------------------------------- 1 | component accessors=true extends='aws' { 2 | 3 | property name='myClient' type='com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient' getter=false setter=false; 4 | property name='dynamodb' type='com.amazonaws.services.dynamodbv2.document.DynamoDB' getter=false setter=false; 5 | 6 | property name='tables' type='struct' getter=false setter=false; 7 | 8 | public dynamodb function init( 9 | string account, 10 | string secret, 11 | string region = 'eu-west-1' 12 | ) { 13 | 14 | super.init( 15 | argumentCollection = arguments 16 | ); 17 | 18 | variables.tables = {}; 19 | 20 | variables.myClient = CreateAWSObject( 'services.dynamodbv2.AmazonDynamoDBClientBuilder' ) 21 | .standard() 22 | .withRegion( arguments.region ) 23 | .withCredentials( getCredentials() ) 24 | .build(); 25 | 26 | variables.dynamodb = CreateAWSObject( 'services.dynamodbv2.document.DynamoDB' ).init( 27 | getMyClient() 28 | ); 29 | 30 | return this; 31 | } 32 | 33 | private function getDynamodb() { 34 | return variables.dynamodb; 35 | } 36 | 37 | private function getTables() { 38 | return variables.tables; 39 | } 40 | 41 | private function getTable( 42 | required string name 43 | ) { 44 | if ( 45 | !StructKeyExists( getTables() , arguments.name ) 46 | ) { 47 | 48 | var table = getDynamodb().getTable( 49 | arguments.name 50 | ); 51 | 52 | // Just do a describe to check the table exists 53 | table.describe(); 54 | 55 | variables.tables[ arguments.name ] = table; 56 | 57 | } 58 | return variables.tables[ arguments.name ]; 59 | } 60 | 61 | public struct function getItem( 62 | required string table, 63 | required string key, 64 | required string value, 65 | string key2, 66 | string value2 67 | ) { 68 | 69 | var table = getTable( 70 | name = arguments.table 71 | ); 72 | 73 | if ( 74 | StructKeyExists( arguments , 'key2' ) 75 | && 76 | StructKeyExists( arguments , 'value2' ) 77 | ) { 78 | var item = table.getItem( 79 | arguments.key, 80 | arguments.value, 81 | arguments.key2, 82 | arguments.value2 83 | ); 84 | } else { 85 | var item = table.getItem( 86 | arguments.key, 87 | arguments.value 88 | ); 89 | } 90 | 91 | return DeserializeJSON( 92 | item.toJSON() 93 | ); 94 | 95 | } 96 | 97 | public any function newItem() { 98 | return CreateAWSObject( 'services.dynamodbv2.document.Item' ).init(); 99 | } 100 | 101 | public void function putItem( 102 | required string table, 103 | required any item 104 | ) { 105 | var table = getTable( 106 | name = arguments.table 107 | ); 108 | 109 | table.putItem( 110 | arguments.item 111 | ); 112 | } 113 | 114 | public array function scan( 115 | required string table, 116 | required string filterExpression, 117 | required string projectionExpression, 118 | struct nameMap, 119 | struct valueMap 120 | ) { 121 | 122 | var table = getTable( 123 | name = arguments.table 124 | ); 125 | 126 | var results = table.scan( 127 | arguments.filterExpression, 128 | arguments.projectionExpression, 129 | arguments.nameMap ?: JavaCast( 'null' , 0 ), 130 | arguments.valueMap ?: JavaCast( 'null' , 0 ) 131 | ).iterator(); 132 | 133 | var rendered_results = []; 134 | 135 | while ( results.hasNext() ) { 136 | rendered_results.add( 137 | DeserializeJSON( 138 | results.next().toJSON() 139 | ) 140 | ); 141 | } 142 | 143 | return rendered_results; 144 | } 145 | 146 | } -------------------------------------------------------------------------------- /elb.cfc: -------------------------------------------------------------------------------- 1 | component accessors=true extends='aws' { 2 | 3 | property name='myClient' type='com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingClient' getter=false setter=false; 4 | 5 | public elb function init( 6 | string account, 7 | string secret, 8 | string region = 'eu-west-1' 9 | ) { 10 | 11 | super.init( 12 | argumentCollection = arguments 13 | ); 14 | 15 | variables.myClient = CreateAWSObject( 'services.elasticloadbalancing.AmazonElasticLoadBalancingClientBuilder' ) 16 | .standard() 17 | .withRegion( arguments.region ) 18 | .withCredentials( getCredentials() ) 19 | .build(); 20 | 21 | return this; 22 | } 23 | 24 | public function getConfig( 25 | required string name 26 | ) { 27 | 28 | var describeLoadBalancerRequest = CreateAWSObject( 'services.elasticloadbalancing.model.DescribeLoadBalancersRequest' ).init( 29 | [ arguments.name ] 30 | ); 31 | 32 | try { 33 | 34 | describeLoadBalancerResponse = getMyClient() 35 | .describeLoadBalancers( 36 | describeLoadBalancerRequest 37 | ) 38 | .getLoadBalancerDescriptions() 39 | [1]; 40 | 41 | return { 42 | 'CanonicalHostedZoneName': describeLoadBalancerResponse.getCanonicalHostedZoneName(), 43 | 'CanonicalHostedZoneNameID': describeLoadBalancerResponse.getCanonicalHostedZoneNameID(), 44 | 'DNSName': describeLoadBalancerResponse.getDNSName(), 45 | 'LoadBalancerName': describeLoadBalancerResponse.getLoadBalancerName() 46 | }; 47 | 48 | } catch ( com.amazonaws.services.elasticloadbalancing.model.LoadBalancerNotFoundException e ) { 49 | 50 | throw( type = 'elb.nonexistant' , detail = arguments.name ); 51 | 52 | } 53 | 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /lambda.cfc: -------------------------------------------------------------------------------- 1 | component accessors=true extends='aws' { 2 | 3 | property name='myClient' type='com.amazonaws.services.lambda.AWSLambdaClient' getter=false setter=false; 4 | 5 | public lambda function init( 6 | string account, 7 | string secret, 8 | string region = 'eu-west-1' 9 | ) { 10 | 11 | super.init( 12 | argumentCollection = arguments 13 | ); 14 | 15 | variables.myClient = CreateAWSObject( 'services.lambda.AWSLambdaClientBuilder' ) 16 | .standard() 17 | .withRegion( arguments.region ) 18 | .withCredentials( getCredentials() ) 19 | .build(); 20 | 21 | return this; 22 | } 23 | 24 | public any function invoke( 25 | required string method, 26 | required struct payload, 27 | string invocationType = 'RequestResponse' 28 | ) { 29 | 30 | var invoke_request = CreateAWSObject( 'services.lambda.model.InvokeRequest' ) 31 | .init() 32 | .withFunctionName( arguments.method ) 33 | .withInvocationType( arguments.invocationType ) 34 | .withPayload( 35 | SerializeJSON( 36 | arguments.payload 37 | ) 38 | ); 39 | 40 | return 41 | DeserializeJSON( 42 | ToString( 43 | getMyClient() 44 | .invoke( invoke_request ) 45 | .getPayload() 46 | .array() 47 | ) 48 | ); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /opsworks.cfc: -------------------------------------------------------------------------------- 1 | component accessors=true extends='aws' { 2 | 3 | property name='opsworksClient' type='com.amazonaws.services.opsworks.AWSOpsWorksClient' getter=false setter=false; 4 | 5 | property name='tables' type='struct' getter=false setter=false; 6 | 7 | public opsworks function init( 8 | string account, 9 | string secret 10 | ) { 11 | 12 | super.init( 13 | argumentCollection = arguments 14 | ); 15 | 16 | variables.myClient = CreateAWSObject( 'services.opsworks.AWSOpsWorksClientBuilder' ) 17 | .standard() 18 | .withCredentials( getCredentials() ) 19 | .build(); 20 | 21 | return this; 22 | } 23 | 24 | public function getOpsworksClient() { 25 | return variables.opsworksClient; 26 | } 27 | 28 | private function getStackOntoDeploymentRequest( 29 | required string stack, 30 | required opsworksClient, 31 | required deploymentRequest 32 | ) { 33 | 34 | for ( var r in arguments.opsworksClient.describeStacks( 35 | CreateAWSObject( 'services.opsworks.model.DescribeStacksRequest' ).init() 36 | ).getStacks() ) { 37 | if ( 38 | r.getName() == arguments.stack 39 | ) { 40 | arguments.deploymentRequest.setStackId( 41 | r.getStackId() 42 | ); 43 | return arguments.deploymentRequest; 44 | break; 45 | } 46 | } 47 | return deploymentRequest; 48 | } 49 | 50 | public function runRecipe( 51 | required string stack, 52 | required string recipe 53 | ) { 54 | 55 | var deploymentRequest = CreateAWSObject( 'services.opsworks.model.CreateDeploymentRequest' ).init(); 56 | 57 | var deploymentCommand = CreateAWSObject( 'services.opsworks.model.DeploymentCommand' ) 58 | .withName( 59 | 'execute_recipes' 60 | ); 61 | 62 | deploymentCommand.setArgs( 63 | { 64 | 'recipes': [ 65 | arguments.recipe 66 | ] 67 | } 68 | ); 69 | 70 | deploymentRequest.setCommand( 71 | deploymentCommand 72 | ); 73 | 74 | var opsworksClient = getOpsworksClient(); 75 | 76 | deploymentRequest = getStackOntoDeploymentRequest( 77 | stack = arguments.stack, 78 | opsworksClient = opsworksClient, 79 | deploymentRequest = deploymentRequest 80 | ); 81 | 82 | opsworksClient.createDeployment( 83 | deploymentRequest 84 | ); 85 | 86 | } 87 | 88 | 89 | public function deploy( 90 | required string stack, 91 | required string app 92 | ) { 93 | var deploymentRequest = CreateAWSObject( 'services.opsworks.model.CreateDeploymentRequest' ).init(); 94 | 95 | var deploymentCommand = CreateAWSObject( 'services.opsworks.model.DeploymentCommand' ) 96 | .withName( 97 | 'deploy' 98 | ); 99 | 100 | deploymentRequest.setCommand( 101 | deploymentCommand 102 | ); 103 | 104 | var opsworksClient = getOpsworksClient(); 105 | 106 | deploymentRequest = getStackOntoDeploymentRequest( 107 | stack = arguments.stack, 108 | opsworksClient = opsworksClient, 109 | deploymentRequest = deploymentRequest 110 | ); 111 | 112 | var describeAppsRequest = CreateAWSObject( 'services.opsworks.model.DescribeAppsRequest' ).init(); 113 | 114 | describeAppsRequest.setStackId( 115 | deploymentRequest.getStackId() 116 | ); 117 | 118 | for ( var r in opsworksClient.describeApps( 119 | describeAppsRequest 120 | ).getApps() ) { 121 | if ( 122 | r.getName() == arguments.app 123 | ) { 124 | deploymentRequest.setAppId( 125 | r.getAppId() 126 | ); 127 | break; 128 | } 129 | } 130 | 131 | opsworksClient.createDeployment( 132 | deploymentRequest 133 | ); 134 | 135 | } 136 | 137 | } -------------------------------------------------------------------------------- /route53.cfc: -------------------------------------------------------------------------------- 1 | component accessors=true extends='aws' { 2 | 3 | property name='elb' type='elb' getter=false setter=false; 4 | property name='myClient' type='services.route53.AmazonRoute53Client' getter=false setter=false; 5 | 6 | public route53 function init( 7 | string account, 8 | string secret 9 | ) { 10 | 11 | super.init( 12 | argumentCollection = arguments 13 | ); 14 | 15 | variables.elb = new elb( 16 | argumentCollection = arguments 17 | ); 18 | 19 | variables.myClient = CreateAWSObject( 'services.route53.AmazonRoute53ClientBuilder' ) 20 | .standard() 21 | .withCredentials( getCredentials() ) 22 | .build(); 23 | 24 | return this; 25 | } 26 | 27 | private any function getHostedZone( 28 | required string domain 29 | ) { 30 | 31 | var target_domain = arguments.domain & '.'; 32 | 33 | var hosted_zones_request = CreateAWSObject( 'services.route53.model.ListHostedZonesByNameRequest' ) 34 | .init() 35 | .withDNSName( target_domain ) 36 | .withMaxItems( 1 ); 37 | 38 | var hosted_zone = getMyClient() 39 | .listHostedZonesByName(hosted_zones_request) 40 | .HostedZones[1]; 41 | 42 | if ( 43 | hosted_zone.Name == target_domain 44 | ) { 45 | return hosted_zone; 46 | } 47 | 48 | throw( type = 'route53.domain.nonexistant' , detail = arguments.domain ); 49 | 50 | } 51 | 52 | private string function getHostedZoneID( 53 | required string domain 54 | ) { 55 | 56 | return getHostedZone( 57 | domain = arguments.domain 58 | ).Id.ListLast( '/' ); 59 | 60 | } 61 | 62 | private any function getResourceRecordForSubdomain( 63 | required string subdomain 64 | ) { 65 | var target_subdomain = arguments.subdomain & '.'; 66 | 67 | var resource_record_sets_request = CreateAWSObject( 'services.route53.model.ListResourceRecordSetsRequest' ) 68 | .init( 69 | getHostedZoneID( 70 | domain = arguments.subdomain.ListDeleteAt( 1 , '.' ) 71 | ) 72 | ) 73 | .withStartRecordName( target_subdomain ); 74 | 75 | var resource_record_set = getMyClient() 76 | .listResourceRecordSets( resource_record_sets_request ) 77 | .ResourceRecordSets[1]; 78 | 79 | if ( 80 | resource_record_set.Name == target_subdomain 81 | ) { 82 | return resource_record_set; 83 | } 84 | 85 | throw( type = 'route53.subdomain.nonexistant' , detail = arguments.subdomain ); 86 | 87 | } 88 | 89 | public boolean function isThereAHostedZoneForThisDomain( 90 | required string domain 91 | ) { 92 | 93 | try { 94 | getHostedZone( 95 | domain = arguments.domain 96 | ); 97 | return true; 98 | } catch ( route53.domain.nonexistant e ) { 99 | return false; 100 | } 101 | 102 | } 103 | 104 | public boolean function isThereAResourceRecordForThisSubdomain( 105 | required string subdomain 106 | ) { 107 | 108 | try { 109 | getResourceRecordForSubdomain( 110 | subdomain = arguments.subdomain 111 | ); 112 | return true; 113 | } catch ( route53.subdomain.nonexistant e ) { 114 | return false; 115 | } 116 | 117 | } 118 | 119 | public route53 function addAliasSubdomain( 120 | required string subdomain, 121 | required string elb_region, 122 | required string elb_name 123 | ) { 124 | 125 | var resource_record_set = CreateAWSObject( 'services.route53.model.ResourceRecordSet' ).init( 126 | arguments.subdomain&'.', 127 | 'A' 128 | ); 129 | 130 | var elbToLinkTo = variables.elb.setRegion( 131 | region = arguments.elb_region 132 | ).getConfig( 133 | name = arguments.elb_name 134 | ); 135 | 136 | var alias_target = CreateAWSObject( 'services.route53.model.AliasTarget' ).init( 137 | elbToLinkTo.CanonicalHostedZoneNameID, 138 | elbToLinkTo.CanonicalHostedZoneName 139 | ); 140 | 141 | alias_target.setEvaluateTargetHealth( false ); 142 | resource_record_set.setAliasTarget( alias_target ); 143 | 144 | var change = CreateAWSObject( 'services.route53.model.Change' ).init( 145 | 'UPSERT', 146 | resource_record_set 147 | ); 148 | 149 | return changeResourceRecordSets( 150 | subdomain = arguments.subdomain, 151 | change = change 152 | ); 153 | 154 | } 155 | 156 | public route53 function deleteSubdomain( 157 | required string subdomain 158 | ) { 159 | 160 | try { 161 | var resource_record_set = getResourceRecordForSubdomain( 162 | subdomain = arguments.subdomain 163 | ); 164 | } catch ( route53.subdomain.nonexistant e ) { 165 | throw('Unable to find resource record for subdomain '&arguments.subdomain); 166 | } 167 | 168 | var change = CreateAWSObject( 'services.route53.model.Change' ).init( 169 | 'DELETE', 170 | resource_record_set 171 | ); 172 | 173 | return changeResourceRecordSets( 174 | subdomain = arguments.subdomain, 175 | change = change 176 | ); 177 | 178 | } 179 | 180 | private route53 function changeResourceRecordSets( 181 | required string subdomain, 182 | required change 183 | ) { 184 | 185 | var tl_domain = arguments.subdomain.ListDeleteAt( 1 , '.' ); 186 | 187 | var route53 = getMyClient(); 188 | 189 | try { 190 | var hosted_zone_id = getHostedZoneID( 191 | domain = tl_domain 192 | ); 193 | } catch ( route53.domain.nonexistant e ) { 194 | throw('Unable to find hosted zone for domain '&tl_domain); 195 | } 196 | 197 | var change_batch = CreateAWSObject( 'services.route53.model.ChangeBatch' ).init( 198 | [ 199 | arguments.change 200 | ] 201 | ); 202 | 203 | var change_resource_record_sets_request = CreateAWSObject( 'services.route53.model.ChangeResourceRecordSetsRequest' ).init( 204 | hosted_zone_id, 205 | change_batch 206 | ); 207 | 208 | route53.changeResourceRecordSets( 209 | change_resource_record_sets_request 210 | ); 211 | 212 | return this; 213 | 214 | } 215 | 216 | } -------------------------------------------------------------------------------- /s3.cfc: -------------------------------------------------------------------------------- 1 | component accessors=true extends='aws' { 2 | 3 | property name='myClient' type='com.amazonaws.services.s3.AmazonS3Client' getter=false setter=false; 4 | property name='bucketACL' type='com.amazonaws.services.s3.model.AccessControlList' getter=false setter=false; 5 | property name='bucket' type='string' getter=false setter=false; 6 | property name='basepath' type='string' getter=false setter=false; 7 | 8 | 9 | public s3 function init( 10 | string account, 11 | string secret, 12 | string region = 'eu-west-1', 13 | required string bucket, 14 | string basepath = '' 15 | ) { 16 | 17 | super.init( 18 | argumentCollection = arguments 19 | ); 20 | 21 | variables.myClient = CreateAWSObject( 'services.s3.AmazonS3ClientBuilder' ) 22 | .standard() 23 | .withRegion( arguments.region ) 24 | .withCredentials( getCredentials() ) 25 | .build(); 26 | 27 | variables.bucket = arguments.bucket; 28 | variables.basepath = arguments.basepath; 29 | 30 | return this; 31 | } 32 | 33 | private any function getBucketACL() { 34 | if ( 35 | !IsDefined( 'variables.bucketACL' ) 36 | ) { 37 | variables.bucketACL = getMyClient().getBucketACL( 38 | variables.bucket 39 | ); 40 | } 41 | 42 | return variables.bucketACL; 43 | } 44 | 45 | public boolean function fileExists( 46 | required string key 47 | ) { 48 | try { 49 | getObjectMetadata( 50 | key = arguments.key 51 | ); 52 | return true; 53 | } catch ( s3.key.nonexistant ) { 54 | return false; 55 | } 56 | } 57 | 58 | public array function directoryList( 59 | string directory = '' 60 | ) { 61 | 62 | var array_of_keys = []; 63 | 64 | var directory_with_trailing_slash = arguments.directory; 65 | 66 | if ( 67 | Len( directory_with_trailing_slash ) > 0 68 | && 69 | Right( arguments.directory , 1 ) != '/' 70 | ) { 71 | directory_with_trailing_slash &= '/'; 72 | } 73 | 74 | var full_path = variables.basepath & directory_with_trailing_slash; 75 | var strip_basepath = ( Len( variables.basepath ) > 0 ); 76 | 77 | var object_listing = getMyClient().listObjects( variables.bucket, full_path ); 78 | 79 | do { 80 | for (var summary in object_listing.getObjectSummaries() ) { 81 | 82 | var key = summary.getKey(); 83 | if ( strip_basepath ) { 84 | key = REReplace( key , '^' & variables.basepath , '' ); 85 | } 86 | 87 | var name = REReplace( key , '^' & directory_with_trailing_slash , '' ); 88 | 89 | if ( Len( name ) > 0 ) { 90 | array_of_keys.add({ 91 | 'key': key, 92 | 'name': name, 93 | 'type': ( Right(key,1) == '/' )?'folder':'item', 94 | 'size': summary.getSize(), 95 | 'lastModified': summary.getLastModified() 96 | }); 97 | } 98 | } 99 | 100 | getMyClient().listNextBatchOfObjects(object_listing); 101 | 102 | } while ( object_listing.isTruncated() ); 103 | 104 | return array_of_keys; 105 | } 106 | 107 | public s3 function copyObject( 108 | required string source, 109 | required string destination 110 | ) { 111 | 112 | // Does the source file exists? 113 | getObjectMetadata( 114 | key = arguments.source 115 | ); 116 | 117 | // Is it trying to copy over itself? 118 | if ( arguments.source == arguments.destination ) { 119 | return this; 120 | } 121 | 122 | getMyClient().copyObject( 123 | variables.bucket, 124 | getKeyFromPath( 125 | key = arguments.source 126 | ), 127 | variables.bucket, 128 | getKeyFromPath( 129 | key = arguments.destination 130 | ) 131 | ); 132 | 133 | return this; 134 | } 135 | 136 | public s3 function moveObject( 137 | required string source, 138 | required string destination 139 | ) { 140 | 141 | copyObject( 142 | source = arguments.source, 143 | destination = arguments.destination 144 | ); 145 | 146 | // Do I need to delete the original? 147 | if ( arguments.source != arguments.destination ) { 148 | deleteObject( 149 | key = arguments.source 150 | ); 151 | } 152 | 153 | return this; 154 | } 155 | 156 | public s3 function makeDirectory( 157 | required string key 158 | ) { 159 | var object_metadata = CreateAWSObject( 'services.s3.model.ObjectMetadata' ).init(); 160 | 161 | var empty_string = ''; 162 | var empty_file = CreateObject( 163 | 'java', 164 | 'java.io.ByteArrayInputStream' 165 | ).init( 166 | empty_string.getBytes('UTF-8') 167 | ); 168 | 169 | getMyClient().putObject( 170 | variables.bucket, 171 | getKeyFromPath( 172 | key = arguments.key 173 | ), 174 | empty_file, 175 | object_metadata 176 | ); 177 | 178 | getMyClient().setObjectAcl( 179 | variables.bucket, 180 | getKeyFromPath( 181 | key = arguments.key 182 | ), 183 | getBucketACL() 184 | ); 185 | 186 | return this; 187 | } 188 | 189 | public s3 function deleteObject( 190 | required string key 191 | ) { 192 | getMyClient().deleteObject( 193 | variables.bucket, 194 | getKeyFromPath( 195 | key = arguments.key 196 | ) 197 | ); 198 | return this; 199 | } 200 | 201 | public struct function getObjectMetadata( 202 | required string key 203 | ) { 204 | var full_key = getKeyFromPath( 205 | key = arguments.key 206 | ); 207 | 208 | try { 209 | 210 | var metadata = getMyClient().getObjectMetadata( 211 | variables.bucket, 212 | full_key 213 | ); 214 | 215 | return { 216 | 'length': metadata.getContentLength(), 217 | 'type': metadata.getContentType() 218 | }; 219 | 220 | } catch( com.amazonaws.services.s3.model.AmazonS3Exception ) { 221 | throw( type = 's3.key.nonexistant' , detail = full_key ); 222 | } 223 | } 224 | 225 | public string function getKeyFromPath( 226 | required string key 227 | ) { 228 | return variables.basepath&arguments.key; 229 | } 230 | 231 | public function getSourceObject( 232 | required string key 233 | ) { 234 | var full_key = getKeyFromPath( 235 | key = arguments.key 236 | ); 237 | 238 | try { 239 | var object = getMyClient().getObject( 240 | variables.bucket, 241 | full_key 242 | ); 243 | } catch( com.amazonaws.services.s3.model.AmazonS3Exception ) { 244 | throw( type = 's3.key.nonexistant' , detail = full_key ); 245 | } 246 | 247 | return object; 248 | } 249 | 250 | public struct function getObject( 251 | required string key 252 | ) { 253 | var object = getSourceObject( 254 | key = arguments.key 255 | ); 256 | 257 | var metadata = object.getObjectMetadata(); 258 | 259 | var input_stream = object.getObjectContent(); 260 | var file_content = CreateObject( 'java' , 'java.io.ByteArrayOutputStream' ).init(); 261 | 262 | while( true ) { 263 | var next = input_stream.read(); 264 | if ( next < 0 ) { 265 | break; 266 | } 267 | file_content.write( next ); 268 | } 269 | 270 | var response = { 271 | 'metadata': { 272 | 'length': metadata.getContentLength(), 273 | 'type': metadata.getContentType() 274 | }, 275 | 'content': BinaryEncode( file_content.toByteArray() , 'Base64' ) 276 | }; 277 | 278 | return response; 279 | 280 | } 281 | 282 | public s3 function putObject( 283 | required string key, 284 | required string object, 285 | string acl = 'inheritFromBucket' 286 | ) { 287 | if ( 288 | !isDataStringValid( 289 | arguments.object 290 | ) 291 | ) { 292 | throw( type = 's3.object.unrecognisedformat' ); 293 | } 294 | 295 | var encoded_data = arguments.object.ListLast( ';' ); 296 | 297 | var binary_data = BinaryDecode( encoded_data.ListLast( ',' ) , encoded_data.ListFirst( ',' ) ); 298 | var mime_type = arguments.object.ListFirst( ';' ).ListLast( ':' ); 299 | 300 | var object_metadata = CreateAWSObject( 'services.s3.model.ObjectMetadata' ).init(); 301 | object_metadata.setContentType( mime_type ); 302 | 303 | var input_stream = CreateObject( 304 | 'java', 305 | 'java.io.ByteArrayInputStream' 306 | ).init( 307 | binary_data 308 | ); 309 | 310 | getMyClient().putObject( 311 | variables.bucket, 312 | getKeyFromPath( 313 | key = arguments.key 314 | ), 315 | input_stream, 316 | object_metadata 317 | ); 318 | 319 | return setObjectAcl( 320 | key = arguments.key, 321 | acl = arguments.acl 322 | ); 323 | } 324 | 325 | public s3 function setObjectAcl( 326 | required string key, 327 | required string acl 328 | ) { 329 | 330 | var acl = ''; 331 | 332 | switch( arguments.acl ) { 333 | case 'AuthenticatedRead': 334 | case 'BucketOwnerFullControl': 335 | case 'BucketOwnerRead': 336 | case 'LogDeliveryWrite': 337 | case 'Private': 338 | case 'PublicRead': 339 | case 'PublicReadWrite': 340 | 341 | acl = CreateAWSObject( 'services.s3.model.CannedAccessControlList' ) 342 | .valueOf( arguments.acl ); 343 | 344 | break; 345 | 346 | case 'inheritFromBucket': 347 | acl = getBucketACL(); 348 | break; 349 | 350 | default: 351 | throw( type = 's3.acl.unrecognisedLevel' , detail = arguments.acl ); 352 | break; 353 | } 354 | 355 | getMyClient().setObjectAcl( 356 | variables.bucket, 357 | getKeyFromPath( 358 | key = arguments.key 359 | ), 360 | acl 361 | ); 362 | 363 | return this; 364 | } 365 | 366 | 367 | private boolean function isDataStringValid( 368 | required string object 369 | ) { 370 | return ( 371 | arguments.object.REFind( 'data:[^/]*/[^;]*;base64,[a-zA-Z0-9+/]+' ) 372 | ); 373 | } 374 | } -------------------------------------------------------------------------------- /ses.cfc: -------------------------------------------------------------------------------- 1 | component accessors=true extends='aws' { 2 | 3 | property name='myClient' type='com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient' getter=false setter=false; 4 | 5 | public ses function init( 6 | string account, 7 | string secret, 8 | string region = 'eu-west-1' 9 | ) { 10 | 11 | super.init( 12 | argumentCollection = arguments 13 | ); 14 | 15 | 16 | variables.myClient = CreateAWSObject( 'services.simpleemail.AmazonSimpleEmailServiceClientBuilder' ) 17 | .standard() 18 | .withRegion( arguments.region ) 19 | .withCredentials( getCredentials() ) 20 | .build(); 21 | 22 | return this; 23 | } 24 | 25 | public struct function getSendQuota() { 26 | 27 | var send_quota = getMyClient().getSendQuota(); 28 | 29 | return { 30 | 'Max24HourSend': send_quota.Max24HourSend, 31 | 'MaxSendRate': send_quota.MaxSendRate, 32 | 'SentLast24Hours': send_quota.SentLast24Hours 33 | }; 34 | 35 | } 36 | 37 | public array function listVerifiedEmailAddresses() { 38 | 39 | return getMyClient() 40 | .listIdentities() 41 | .getIdentities(); 42 | 43 | } 44 | 45 | public ses function verifyEmailAddress( 46 | required string email 47 | ) { 48 | 49 | var verify_email = CreateAWSObject( 'services.simpleemail.model.VerifyEmailIdentityRequest' ) 50 | .init() 51 | .withEmailAddress( arguments.email ); 52 | 53 | getMyClient().verifyEmailIdentity( 54 | verify_email 55 | ); 56 | 57 | return this; 58 | } 59 | 60 | public ses function deleteVerifiedEmailAddress( 61 | required string email 62 | ) { 63 | 64 | var delete_email = CreateAWSObject( 'services.simpleemail.model.DeleteIdentityRequest' ) 65 | .init() 66 | .withIdentity( arguments.email ); 67 | 68 | getMyClient().deleteIdentity( 69 | delete_email 70 | ); 71 | 72 | 73 | return this; 74 | } 75 | 76 | public ses function sendEmail( 77 | required string from, 78 | required string to, 79 | required string subject, 80 | required string body, 81 | string format = 'plain', 82 | string cc, 83 | string bcc 84 | ) { 85 | 86 | var email_subject = CreateAWSObject( 'services.simpleemail.model.Content' ).init( 87 | arguments.subject 88 | ); 89 | 90 | var email_body_content = CreateAWSObject( 'services.simpleemail.model.Content' ).init( 91 | arguments.body 92 | ); 93 | 94 | var email_body = CreateAWSObject( 'services.simpleemail.model.Body' ).init(); 95 | 96 | switch( arguments.format ) { 97 | case 'html': 98 | email_body.setHtml( email_body_content ); 99 | break; 100 | case 'plain': 101 | default: 102 | email_body.setText( email_body_content ); 103 | break; 104 | } 105 | 106 | var email_message = CreateAWSObject( 'services.simpleemail.model.Message' ).init( 107 | email_subject, 108 | email_body 109 | ); 110 | 111 | 112 | var destination = CreateAWSObject( 'services.simpleemail.model.Destination' ) 113 | .init() 114 | .withToAddresses( arguments.to.ListToArray( ';' ) ); 115 | 116 | if ( 117 | StructKeyExists( arguments , 'cc' ) 118 | ) { 119 | destination.setCcAddresses( arguments.cc.ListToArray( ';' ) ); 120 | } 121 | 122 | if ( 123 | StructKeyExists( arguments , 'bcc' ) 124 | ) { 125 | destination.setBccAddresses( arguments.bcc.ListToArray( ';' ) ); 126 | } 127 | 128 | var send_email_request = CreateAWSObject( 'services.simpleemail.model.SendEmailRequest' ) 129 | .init() 130 | .withDestination( destination ) 131 | .withSource( arguments.from ) 132 | .withMessage( email_message ); 133 | 134 | getMyClient().sendEmail( 135 | send_email_request 136 | ); 137 | 138 | return this; 139 | } 140 | 141 | public ses function sendRawEmail( 142 | required string data 143 | ) { 144 | 145 | var email_message = CreateAWSObject( 'services.simpleemail.model.RawMessage' ).init( 146 | CreateObject( 147 | 'java', 148 | 'java.nio.charset.Charset' 149 | ) 150 | .forName( 'UTF-8' ) 151 | .newEncoder() 152 | .encode( 153 | CreateObject( 154 | 'java', 155 | 'java.nio.CharBuffer' 156 | ).wrap( 157 | arguments.data 158 | ) 159 | ) 160 | ); 161 | 162 | var send_raw_email_request = CreateAWSObject( 'services.simpleemail.model.SendRawEmailRequest' ) 163 | .init() 164 | .withRawMessage( email_message ); 165 | 166 | getMyClient().sendRawEmail( 167 | send_raw_email_request 168 | ); 169 | 170 | return this; 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /tests/Application.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | this.name = 'lucee-aws_' & Hash( GetCurrentTemplatePath() ); 3 | 4 | this.mappings[ '/testbox' ] = ExpandPath( '../testbox' ); 5 | this.mappings[ '/tests' ] = ExpandPath( './' ); 6 | this.mappings[ '/aws' ] = ExpandPath( '../' ); 7 | 8 | public boolean function onApplicationStart() { 9 | 10 | var env = CreateObject( 'java' , 'java.lang.System' ).getenv(); 11 | 12 | application.aws_settings = { 13 | 'aws_accountid': '', // self explanatory, DO NOT COMMIT TO A PUBLIC REPO 14 | 'aws_secretkey': '', // self explanatory, DO NOT COMMIT TO A PUBLIC REPO 15 | 'dynamodb_table': '', // a dynamodb table with some keys that i can't remember 16 | 'elb_name': '', // subdomain of a loadbalancer 17 | 'elb_region': '', // region that the elb_name is in 18 | 'lambda_method': '', // name of a lambda method that takes in {key1='',key2='',key3=''} and returns a concat string 19 | 'route53_tld': '', // a hosted zone domain name i.e. something.com 20 | 'ses_from': '', // email address that can send from SES for you 21 | 'ses_to': '', // email address that can receive email from SES for you 22 | 's3_bucket': '' // name of an s3 bucket 23 | }; 24 | 25 | for( key in env ) { 26 | if ( 27 | StructKeyExists( application.aws_settings , key ) 28 | ) { 29 | application.aws_settings[ key ] = env[ key ]; 30 | } 31 | } 32 | 33 | return true; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /tests/aws.cfc: -------------------------------------------------------------------------------- 1 | component extends='testbox.system.BaseSpec' { 2 | 3 | function run() { 4 | 5 | describe( 'aws' , function() { 6 | 7 | beforeEach( function( currentSpec ) { 8 | service = new aws.aws( 9 | account = application.aws_settings.aws_accountid, 10 | secret = application.aws_settings.aws_secretkey 11 | ); 12 | }); 13 | 14 | it( 'can login and has a config object stored internally' , function() { 15 | 16 | makePublic( service , 'getCredentials' , 'getCredentials' ); 17 | 18 | actual = service.getCredentials(); 19 | 20 | expect( 21 | actual.getClass().getName() 22 | ).toBe( 23 | 'com.amazonaws.auth.BasicAWSCredentials' 24 | ); 25 | 26 | }); 27 | 28 | it( 'has regions stored' , function() { 29 | 30 | makePublic( service , 'getRegions' , 'getRegions' ); 31 | 32 | actual = service.getRegions(); 33 | 34 | expect( 35 | actual.getClass().getName() 36 | ).toBe( 37 | 'com.amazonaws.regions.Regions' 38 | ); 39 | 40 | }); 41 | 42 | it( 'can return eu-west-1' , function() { 43 | 44 | actual = service.getRegion( 45 | region = 'eu-west-1' 46 | ); 47 | 48 | expect( 49 | actual.toString() 50 | ).toBe( 51 | 'EU_WEST_1' 52 | ); 53 | 54 | }); 55 | 56 | it( 'defaults to eu-west-1 because that is where I live' , function() { 57 | 58 | actual = service.getRegion(); 59 | expected = service.getRegion( 60 | region = 'eu-west-1' 61 | ); 62 | 63 | expect( actual.toString() ).toBe( expected.toString() ); 64 | 65 | }); 66 | 67 | }); 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tests/dynamodb.cfc: -------------------------------------------------------------------------------- 1 | component extends='testbox.system.BaseSpec' { 2 | 3 | function run() { 4 | 5 | describe( 'dynamodb' , function() { 6 | 7 | beforeEach( function( currentSpec ) { 8 | service = new aws.dynamodb( 9 | account = application.aws_settings.aws_accountid, 10 | secret = application.aws_settings.aws_secretkey, 11 | region = 'eu-west-1' 12 | ); 13 | }); 14 | 15 | it( 'extends aws' , function() { 16 | 17 | expect( 18 | service 19 | ).toBeInstanceOf( 20 | 'aws.aws' 21 | ); 22 | 23 | }); 24 | 25 | 26 | it( 'has a dynamodb client stored' , function() { 27 | 28 | makePublic( service , 'getMyClient' , 'getMyClient' ); 29 | 30 | actual = service.getMyClient(); 31 | 32 | expect( 33 | actual.getClass().getName() 34 | ).toBe( 35 | 'com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient' 36 | ); 37 | 38 | }); 39 | 40 | 41 | it( 'has a dynamodb service stored' , function() { 42 | 43 | makePublic( service , 'getDynamodb' , 'getDynamodb' ); 44 | 45 | actual = service.getDynamodb(); 46 | 47 | expect( 48 | actual.getClass().getName() 49 | ).toBe( 50 | 'com.amazonaws.services.dynamodbv2.document.DynamoDB' 51 | ); 52 | 53 | }); 54 | 55 | describe( 'getTable()' , function() { 56 | 57 | beforeEach( function( currentSpec ) { 58 | makePublic( service , 'getTable' , 'getTable' ); 59 | }); 60 | 61 | it( 'can get a table' , function() { 62 | 63 | actual = service.getTable( 64 | application.aws_settings.dynamodb_table 65 | ); 66 | 67 | expect( 68 | actual.getClass().getName() 69 | ).toBe( 70 | 'com.amazonaws.services.dynamodbv2.document.Table' 71 | ); 72 | }); 73 | 74 | it( 'throws an error for a nonexistant table' , function() { 75 | 76 | expect( function() { 77 | 78 | service.getTable( 79 | 'i-do-not-exist' 80 | ); 81 | 82 | }).toThrow( 83 | 84 | ); 85 | 86 | }); 87 | 88 | it( 'caches requested tables' , function() { 89 | 90 | makePublic( service , 'getTables' , 'getTables' ); 91 | 92 | before = service.getTables(); 93 | 94 | expect( before ).toBe( {} ); 95 | 96 | service.getTable( 97 | application.aws_settings.dynamodb_table 98 | ); 99 | 100 | actual = service.getTables(); 101 | 102 | expect( 103 | actual 104 | ).toHaveKey( 105 | application.aws_settings.dynamodb_table 106 | ); 107 | 108 | expect( 109 | actual[application.aws_settings.dynamodb_table].getClass().getName() 110 | ).toBe( 111 | 'com.amazonaws.services.dynamodbv2.document.Table' 112 | ); 113 | 114 | }); 115 | 116 | 117 | }); 118 | 119 | describe( 'getItem()' , function() { 120 | 121 | 122 | it( 'can get a structure using a hash+range lookup' , function() { 123 | 124 | actual = service.getItem( 125 | table = application.aws_settings.dynamodb_table, 126 | key = 'key1', 127 | value = 'hobo', 128 | key2 = 'key2', 129 | value2 = 'bot' 130 | ); 131 | 132 | expected = { 133 | 'key1': 'hobo', 134 | 'key2': 'bot', 135 | 'company': 'strayegg', 136 | 'lego': true 137 | }; 138 | 139 | expect ( actual ).toBe( expected ); 140 | 141 | }); 142 | 143 | 144 | 145 | it( 'returns an empty structure for a nonexistant record' , function() { 146 | 147 | expect( function() { 148 | 149 | service.getItem( 150 | table = application.aws_settings.dynamodb_table, 151 | key = 'company', 152 | value = GetTickCount() 153 | ); 154 | 155 | }).toThrow( 156 | 'com.amazonaws.services.dynamodbv2.model.AmazonDynamoDBException' 157 | ); 158 | 159 | }); 160 | 161 | 162 | }); 163 | 164 | }); 165 | 166 | 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /tests/elb.cfc: -------------------------------------------------------------------------------- 1 | component extends='testbox.system.BaseSpec' { 2 | 3 | function run() { 4 | 5 | describe( 'route53' , function() { 6 | 7 | beforeEach( function( currentSpec ) { 8 | service = new aws.elb( 9 | account = application.aws_settings.aws_accountid, 10 | secret = application.aws_settings.aws_secretkey, 11 | region = application.aws_settings.elb_region 12 | ); 13 | }); 14 | 15 | it( 'extends aws' , function() { 16 | 17 | expect( 18 | service 19 | ).toBeInstanceOf( 20 | 'aws.aws' 21 | ); 22 | 23 | }); 24 | 25 | it( 'has a ELB client stored' , function() { 26 | 27 | makePublic( service , 'getMyClient' , 'getMyClient' ); 28 | 29 | actual = service.getMyClient(); 30 | 31 | expect( 32 | actual.getClass().getName() 33 | ).toBe( 34 | 'com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingClient' 35 | ); 36 | 37 | }); 38 | 39 | describe( 'getConfig()' , function() { 40 | 41 | it( 'returns expected values for a defined load balancer' , function() { 42 | 43 | actual = service.getConfig( 44 | name = application.aws_settings.elb_name 45 | ); 46 | 47 | expect( actual ).toHaveKey( 'CanonicalHostedZoneName' ); 48 | expect( actual ).toHaveKey( 'CanonicalHostedZoneNameID' ); 49 | expect( actual ).toHaveKey( 'DNSName' ); 50 | expect( actual ).toHaveKey( 'LoadBalancerName' ); 51 | 52 | expect( actual.CanonicalHostedZoneName ).toBeString(); 53 | expect( actual.CanonicalHostedZoneNameID ).toBeString(); 54 | expect( actual.DNSName ).toBeString(); 55 | expect( actual.LoadBalancerName ).toBeString(); 56 | 57 | }); 58 | 59 | it( 'errors for a fake ELB' , function() { 60 | 61 | expect( function() { 62 | service.getConfig( 63 | name = 'some-fake-load-balancer' 64 | ); 65 | } ).toThrow( 'elb.nonexistant' ); 66 | 67 | }); 68 | 69 | }); 70 | 71 | 72 | 73 | }); 74 | 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /tests/index.cfm: -------------------------------------------------------------------------------- 1 | 2 | setting 3 | showdebugoutput = false; 4 | 5 | url.cpu = url.cpu ?: false; 6 | 7 | rootMapping = '/tests'; 8 | rootPath = ( DirectoryExists( rootMapping ) ) ? rootMapping : ExpandPath( rootMapping ); 9 | 10 | url.path = UrlDecode( url.path ?: '/' ); 11 | if ( 12 | Len( url.path ) == 0 13 | ) { 14 | url.path = '/'; 15 | } 16 | 17 | testbox = new testbox.system.TestBox(); 18 | 19 | switch ( url.action ?: '' ) { 20 | case 'runTestBox': 21 | 22 | if ( 23 | DirectoryExists( 24 | ExpandPath( 25 | rootMapping & url.path 26 | ) 27 | ) 28 | ) { 29 | WriteOutput( 30 | testbox 31 | .init( 32 | directory={ 33 | 'mapping': 'tests', 34 | 'recurse': true, 35 | 'filter': function( 36 | required string path 37 | ) { 38 | return ( 39 | ListLast( arguments.path , '/' ) != 'Application.cfc' 40 | ); 41 | } 42 | } 43 | ) 44 | .run() 45 | ); 46 | } else { 47 | WriteOutput( 48 | '

Invalid incoming directory: ' & rootMapping & url.path & '

' 49 | ); 50 | } 51 | 52 | abort; 53 | break; 54 | } 55 | 56 | directory 57 | action = 'list' 58 | directory = rootPath & url.path 59 | name = 'qResults' 60 | sort = 'asc'; 61 | 62 | executePath = rootMapping & url.path; 63 | 64 | if ( 65 | url.path != '/' 66 | ) { 67 | executePath &= '/'; 68 | 69 | backPath = url.path 70 | .ReplaceNoCase( url.path.ListLast( '/' ) , '' ) 71 | .ReReplace( '/$', '' ); 72 | } 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | TestBox Global Runner 83 | 84 | 100 | 172 | 173 | 174 | 175 | 176 | 177 |
178 |
179 | 180 | 181 |
182 |
v#testbox.getVersion()#
183 | 184 | 185 |
186 | 187 |
188 |

TestBox Test Browser:

189 |

190 | Below is a listing of the files and folders starting from your root #rootPath#. You can click on individual tests in order to execute them 191 | or click on the Run All button on your left and it will execute a directory runner from the visible folder. 192 |

193 | 194 |
Contents: #executePath# 195 | 196 |

197 |
198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | +#qResults.name#
206 | 207 | target="_blank"
>#qResults.name#
208 | 209 | #qResults.name#
210 | 211 | 212 |
213 |
214 | 215 |
216 | 217 |
218 |
219 | 220 | 221 |
222 | 223 | 224 | 225 |
-------------------------------------------------------------------------------- /tests/lambda.cfc: -------------------------------------------------------------------------------- 1 | component extends='testbox.system.BaseSpec' { 2 | 3 | function run() { 4 | 5 | describe( 'lambda' , function() { 6 | 7 | beforeEach( function( currentSpec ) { 8 | service = new aws.lambda( 9 | account = application.aws_settings.aws_accountid, 10 | secret = application.aws_settings.aws_secretkey, 11 | region = application.aws_settings.elb_region 12 | ); 13 | }); 14 | 15 | it( 'extends aws' , function() { 16 | 17 | expect( 18 | service 19 | ).toBeInstanceOf( 20 | 'aws.aws' 21 | ); 22 | 23 | }); 24 | 25 | it( 'has a Lambda client stored' , function() { 26 | 27 | makePublic( service , 'getMyClient' , 'getMyClient' ); 28 | 29 | actual = service.getMyClient(); 30 | 31 | expect( 32 | actual.getClass().getName() 33 | ).toBe( 34 | 'com.amazonaws.services.lambda.AWSLambdaClient' 35 | ); 36 | 37 | }); 38 | 39 | describe( 'invoke()' , function() { 40 | 41 | it( 'returns expected response' , function() { 42 | 43 | payload = { 44 | 'key1': CreateUUID(), 45 | 'key2': CreateUUID(), 46 | 'key3': CreateUUID() 47 | }; 48 | 49 | actual = service.invoke( 50 | method = application.aws_settings.lambda_method, 51 | payload = payload 52 | ); 53 | 54 | expected = payload.key1&':'&payload.key2&'|'&payload.key3; 55 | 56 | expect( actual ).toBe( expected ); 57 | 58 | }); 59 | 60 | }); 61 | 62 | }); 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /tests/route53.cfc: -------------------------------------------------------------------------------- 1 | component extends='testbox.system.BaseSpec' { 2 | 3 | function run() { 4 | 5 | describe( 'route53' , function() { 6 | 7 | beforeEach( function( currentSpec ) { 8 | service = new aws.route53( 9 | account = application.aws_settings.aws_accountid, 10 | secret = application.aws_settings.aws_secretkey 11 | ); 12 | }); 13 | 14 | it( 'extends aws' , function() { 15 | 16 | expect( 17 | service 18 | ).toBeInstanceOf( 19 | 'aws.aws' 20 | ); 21 | 22 | }); 23 | 24 | it( 'has a Route53 client stored' , function() { 25 | 26 | makePublic( service , 'getMyClient' , 'getMyClient' ); 27 | 28 | actual = service.getMyClient(); 29 | 30 | expect( 31 | actual.getClass().getName() 32 | ).toBe( 33 | 'com.amazonaws.services.route53.AmazonRoute53Client' 34 | ); 35 | 36 | }); 37 | 38 | describe( 'getHostedZone()' , function() { 39 | 40 | beforeEach( function() { 41 | 42 | makePublic( service , 'getHostedZone' , 'getHostedZone' ); 43 | 44 | }); 45 | 46 | 47 | it( 'returns hosted zone object for a defined top level domain' , function() { 48 | 49 | actual = service.getHostedZone( 50 | domain = application.aws_settings.route53_tld 51 | ); 52 | 53 | expect( 54 | actual.getClass().getName() 55 | ).toBe( 56 | 'com.amazonaws.services.route53.model.HostedZone' 57 | ); 58 | 59 | }); 60 | 61 | it( 'errors for a fake domain' , function() { 62 | 63 | expect( function() { 64 | service.getHostedZone( 65 | domain = 'some-fake-domain.com' 66 | ); 67 | } ).toThrow( 'route53.domain.nonexistant' ); 68 | 69 | }); 70 | 71 | }); 72 | 73 | 74 | describe( 'getHostedZoneID()' , function() { 75 | 76 | beforeEach( function() { 77 | 78 | makePublic( service , 'getHostedZoneID' , 'getHostedZoneID' ); 79 | 80 | }); 81 | 82 | 83 | it( 'returns string hosted zone ID for known domain' , function() { 84 | 85 | actual = service.getHostedZoneID( 86 | domain = application.aws_settings.route53_tld 87 | ); 88 | 89 | expect( actual ).toBeString(); 90 | expect( actual ).toHaveLength( 13 ); 91 | 92 | }); 93 | 94 | it( 'errors for a fake domain' , function() { 95 | 96 | expect( function() { 97 | service.getHostedZoneID( 98 | domain = 'some-fake-domain.com' 99 | ); 100 | } ).toThrow( 'route53.domain.nonexistant' ); 101 | 102 | }); 103 | 104 | }); 105 | 106 | 107 | describe( 'getResourceRecordForSubdomain()' , function() { 108 | 109 | beforeEach( function() { 110 | 111 | makePublic( service , 'getResourceRecordForSubdomain' , 'getResourceRecordForSubdomain' ); 112 | 113 | }); 114 | 115 | 116 | it( 'returns hosted zone object for a defined subdomain' , function() { 117 | 118 | actual = service.getResourceRecordForSubdomain( 119 | subdomain = generateSubdomainName( 'exists' ) 120 | ); 121 | 122 | expect( 123 | actual.getClass().getName() 124 | ).toBe( 125 | 'com.amazonaws.services.route53.model.ResourceRecordSet' 126 | ); 127 | 128 | }); 129 | 130 | it( 'errors for a fake subdomain' , function() { 131 | 132 | expect( function() { 133 | service.getResourceRecordForSubdomain( 134 | subdomain = generateSubdomainName( 'does-not-exist' ) 135 | ); 136 | } ).toThrow( 'route53.subdomain.nonexistant' ); 137 | 138 | }); 139 | 140 | it( 'errors for a fake domain' , function() { 141 | 142 | expect( function() { 143 | service.getResourceRecordForSubdomain( 144 | subdomain = 'i.really-dont-exist.com' 145 | ); 146 | } ).toThrow( 'route53.domain.nonexistant' ); 147 | 148 | }); 149 | 150 | }); 151 | 152 | describe( 'isThereAHostedZoneForThisDomain()' , function() { 153 | 154 | it( 'returns true for a defined top level domain' , function() { 155 | 156 | expect( 157 | service.isThereAHostedZoneForThisDomain( 158 | domain = application.aws_settings.route53_tld 159 | ) 160 | ).toBeTrue(); 161 | 162 | }); 163 | 164 | it( 'returns false for a fake domain' , function() { 165 | 166 | expect( 167 | service.isThereAHostedZoneForThisDomain( 168 | domain = 'some-fake-domain.com' 169 | ) 170 | ).toBeFalse(); 171 | 172 | }); 173 | 174 | }); 175 | 176 | describe( 'isThereAResourceRecordForThisSubdomain()' , function() { 177 | 178 | it( 'returns true for a defined subdomain' , function() { 179 | 180 | expect( 181 | service.isThereAResourceRecordForThisSubdomain( 182 | subdomain = generateSubdomainName( 'exists' ) 183 | ) 184 | ).toBeTrue(); 185 | 186 | }); 187 | 188 | it( 'returns false for a fake domain' , function() { 189 | 190 | expect( 191 | service.isThereAResourceRecordForThisSubdomain( 192 | subdomain = generateSubdomainName( 'does-not-exist' ) 193 | ) 194 | ).toBeFalse(); 195 | 196 | }); 197 | 198 | }); 199 | 200 | describe( 'addAliasSubdomain() and deleteSubdomain()' , function() { 201 | 202 | it( 'can alias a subdomain using supplied hostedZoneID and ELB target and then delete it' , function() { 203 | 204 | example_subdomain = generateSubdomainName( CreateUUID() ); 205 | 206 | expect( 207 | service.isThereAResourceRecordForThisSubdomain( subdomain = example_subdomain ) 208 | ).toBeFalse(); 209 | 210 | service.addAliasSubdomain( 211 | subdomain = example_subdomain, 212 | elb_region = application.aws_settings.elb_region, 213 | elb_name = application.aws_settings.elb_name 214 | ); 215 | 216 | expect( 217 | service.isThereAResourceRecordForThisSubdomain( subdomain = example_subdomain ) 218 | ).toBeTrue(); 219 | 220 | service.deleteSubdomain( 221 | subdomain = example_subdomain 222 | ); 223 | 224 | expect( 225 | service.isThereAResourceRecordForThisSubdomain( subdomain = example_subdomain ) 226 | ).toBeFalse(); 227 | 228 | }); 229 | 230 | }); 231 | 232 | 233 | 234 | }); 235 | 236 | } 237 | 238 | private string function generateSubdomainName( 239 | required string name 240 | ) { 241 | return arguments.name&'.'&application.aws_settings.route53_tld; 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /tests/runtests.cfm: -------------------------------------------------------------------------------- 1 | 2 | function exitCode( required numeric code ) { 3 | var exitcodeFile = GetDirectoryFromPath( GetCurrentTemplatePath() ) & "/.exitcode"; 4 | FileWrite( exitcodeFile, code ); 5 | } 6 | try { 7 | reporter = cgi.server_protocol == "CLI/1.0" ? "text" : "simple"; 8 | testbox = new testbox.system.TestBox( options={}, reporter=reporter, directory={ 9 | recurse = true 10 | , mapping = "tests" 11 | , filter = function( required path ){ 12 | return ( ListLast( arguments.path , '/' ) != 'Application.cfc' ); 13 | } 14 | } ); 15 | echo( testbox.run() ); 16 | resultObject = testbox.getResult(); 17 | errors = resultObject.getTotalFail() + resultObject.getTotalError(); 18 | exitCode( errors ? 1 : 0 ); 19 | } catch ( any e ) { 20 | echo( "An error occurred running the tests. Message: [#e.message#], Detail: [#e.detail#]" ); 21 | exitCode( 1 ); 22 | } 23 | -------------------------------------------------------------------------------- /tests/ses.cfc: -------------------------------------------------------------------------------- 1 | component extends='testbox.system.BaseSpec' { 2 | 3 | function run() { 4 | 5 | describe( 'ses' , function() { 6 | 7 | beforeEach( function( currentSpec ) { 8 | service = new aws.ses( 9 | account = application.aws_settings.aws_accountid, 10 | secret = application.aws_settings.aws_secretkey, 11 | region = application.aws_settings.elb_region 12 | ); 13 | }); 14 | 15 | it( 'extends aws' , function() { 16 | 17 | expect( 18 | service 19 | ).toBeInstanceOf( 20 | 'aws.aws' 21 | ); 22 | 23 | }); 24 | 25 | it( 'has an SES client stored' , function() { 26 | 27 | makePublic( service , 'getMyClient' , 'getMyClient' ); 28 | 29 | actual = service.getMyClient(); 30 | 31 | expect( 32 | actual.getClass().getName() 33 | ).toBe( 34 | 'com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient' 35 | ); 36 | 37 | }); 38 | 39 | describe( 'getSendQuota()' , function() { 40 | 41 | it( 'returns the current users quota' , function() { 42 | 43 | actual = service.getSendQuota(); 44 | 45 | expect( actual ).toBeStruct(); 46 | 47 | expect( actual ).toHaveKey( 'Max24HourSend' ); 48 | expect( actual ).toHaveKey( 'MaxSendRate' ); 49 | expect( actual ).toHaveKey( 'SentLast24Hours' ); 50 | 51 | expect( actual.Max24HourSend ).toBeNumeric(); 52 | expect( actual.MaxSendRate ).toBeNumeric(); 53 | expect( actual.SentLast24Hours ).toBeNumeric(); 54 | 55 | expect( actual.Max24HourSend ).toBe( 50000 ); 56 | expect( actual.MaxSendRate ).toBe( 14 ); 57 | 58 | }); 59 | 60 | }); 61 | 62 | describe( 'listVerifiedEmailAddresses()' , function() { 63 | 64 | it( 'has only got the to and from addresses in Application' , function() { 65 | 66 | actual = service.listVerifiedEmailAddresses(); 67 | 68 | expect( actual ).toInclude( application.aws_settings.ses_to ); 69 | expect( actual ).toInclude( application.aws_settings.ses_from ); 70 | 71 | }); 72 | 73 | }); 74 | 75 | describe( 'sendEmail()' , function() { 76 | 77 | it( 'can send am email without erroring' , function() { 78 | 79 | service.sendEmail( 80 | to = application.aws_settings.ses_to, 81 | from = application.aws_settings.ses_from, 82 | subject = 'lucee-aws test email '&GetTickCount(), 83 | body = 'This is just some plain text', 84 | format = 'plain' 85 | ); 86 | 87 | }); 88 | 89 | }); 90 | 91 | describe( 'sendRawEmail()' , function() { 92 | 93 | it( 'can send am email without erroring' , function() { 94 | 95 | example_raw_email = 'Received: from smtp-out.example.com (123.45.67.89) by 96 | in.example.com (87.65.43.210); Wed, 2 Mar 2011 11:39:39 -0800 97 | From: '&application.aws_settings.ses_from&' 98 | To: '&application.aws_settings.ses_to&' 99 | Subject: lucee-aws raw test email '&GetTickCount()&' 100 | Message-ID: <97DCB304-C529-4779-BEBC-FC8357FCC4D2@lucee-aws.com> 101 | MIME-Version: 1.0 102 | Content-Type: multipart/mixed; 103 | boundary="_003_97DCB304C5294779BEBCFC8357FCC4D2" 104 | 105 | --_003_97DCB304C5294779BEBCFC8357FCC4D2 106 | Content-Type: text/plain; charset="us-ascii" 107 | Content-Transfer-Encoding: quoted-printable 108 | 109 | This is an email sent by the unit tester 110 | 111 | --_003_97DCB304C5294779BEBCFC8357FCC4D2'; 112 | 113 | service.sendRawEmail( 114 | data = example_raw_email 115 | ); 116 | 117 | }); 118 | 119 | }); 120 | 121 | describe( 'verifyEmailAddress() and deleteVerifiedEmailAddress()' , function() { 122 | 123 | it( 'can verify an email address and then delete it' , function() { 124 | 125 | var test_email = GetTickCount()&'@lucee-aws.com'; 126 | 127 | expect( service.listVerifiedEmailAddresses() ).notToInclude( test_email ); 128 | 129 | service.verifyEmailAddress( 130 | email = test_email 131 | ); 132 | 133 | expect( service.listVerifiedEmailAddresses() ).toInclude( test_email ); 134 | 135 | service.deleteVerifiedEmailAddress( 136 | email = test_email 137 | ); 138 | 139 | expect( service.listVerifiedEmailAddresses() ).notToInclude( test_email ); 140 | 141 | }); 142 | 143 | it( 'just silently does nothing for a nonexistant email' , function() { 144 | 145 | var test_email = 'is_not_verified@lucee-aws.com'; 146 | 147 | expect( service.listVerifiedEmailAddresses() ).notToInclude( test_email ); 148 | 149 | service.deleteVerifiedEmailAddress( 150 | email = test_email 151 | ); 152 | 153 | expect( service.listVerifiedEmailAddresses() ).notToInclude( test_email ); 154 | 155 | }); 156 | 157 | }); 158 | 159 | }); 160 | 161 | } 162 | 163 | } 164 | --------------------------------------------------------------------------------